]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Add basic support for using C++ libraries wip/cpp
authorLuca Bruno <lucabru@src.gnome.org>
Sat, 31 Mar 2012 20:56:00 +0000 (22:56 +0200)
committerLuca Bruno <lucabru@src.gnome.org>
Wed, 11 Apr 2012 15:16:48 +0000 (17:16 +0200)
15 files changed:
ccode/Makefile.am
ccode/valacppdeletestatement.vala [new file with mode: 0644]
ccode/valacppobjectcreation.vala [new file with mode: 0644]
codegen/Makefile.am
codegen/valaccodeattribute.vala
codegen/valaccodebasemodule.vala
codegen/valaccodecompiler.vala
codegen/valaccodememberaccessmodule.vala
codegen/valaccodemethodcallmodule.vala
codegen/valacppmodule.vala [new file with mode: 0644]
codegen/valadovabasemodule.vala
codegen/valagerrormodule.vala
vala/valacodecontext.vala
vala/valasourcefile.vala
vala/valasymbol.vala

index c63dd06e09c687676b46dfb884fa4797ae48910d..fbf81dfdec410f20be6a702731f3bfc862c65078 100644 (file)
@@ -64,6 +64,8 @@ libvalaccode_la_VALASOURCES = \
        valaccodewhilestatement.vala \
        valaccodewriter.vala \
        valaccodeelementaccess.vala \
+       valacppdeletestatement.vala \
+       valacppobjectcreation.vala \
        $(NULL)
 
 libvalaccode_la_SOURCES = \
diff --git a/ccode/valacppdeletestatement.vala b/ccode/valacppdeletestatement.vala
new file mode 100644 (file)
index 0000000..ba62964
--- /dev/null
@@ -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/valacppobjectcreation.vala b/ccode/valacppobjectcreation.vala
new file mode 100644 (file)
index 0000000..47e33b8
--- /dev/null
@@ -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);
+       }
+}
index 2535a88def83851f1b36db7814caed53c1d50efb..dbf558f89fc6085f915b2ef2b97e044d50e9ceba 100644 (file)
@@ -27,6 +27,7 @@ libvala_la_VALASOURCES = \
        valaccodemethodmodule.vala \
        valaccodestructmodule.vala \
        valaclassregisterfunction.vala \
+       valacppmodule.vala \
        valactype.vala \
        valadovaarraymodule.vala \
        valadovaassignmentmodule.vala \
index f22598b761384bdf3a4474bb3ae3d57d9104adfa..1113a3220567206f342d7d0280427b99152a9544 100644 (file)
@@ -468,6 +468,36 @@ public class Vala.CCodeAttribute : AttributeCache {
                }
        }
 
+       public bool cpp {
+               get {
+                       if (_cpp == null) {
+                               if (ccode != null && ccode.has_argument ("cpp")) {
+                                       _cpp = ccode.get_bool ("cpp");
+                               } else if (sym.parent_symbol != null) {
+                                       _cpp = CCodeBaseModule.get_ccode_cpp (sym.parent_symbol);
+                               } else {
+                                       _cpp = false;
+                               }
+                       }
+                       return _cpp;
+               }
+       }
+
+       public bool camelcase {
+               get {
+                       if (_camelcase == null) {
+                               if (ccode != null && ccode.has_argument ("camelcase")) {
+                                       _camelcase = ccode.get_bool ("camelcase");
+                               } else if (sym.parent_symbol != null) {
+                                       _camelcase = CCodeBaseModule.get_ccode_camelcase (sym.parent_symbol);
+                               } else {
+                                       _camelcase = false;
+                               }
+                       }
+                       return _camelcase;
+               }
+       }
+
        public bool array_length { get; private set; }
        public string? array_length_type { get; private set; }
        public bool array_null_terminated { get; private set; }
@@ -511,6 +541,8 @@ public class Vala.CCodeAttribute : AttributeCache {
        private string _finish_real_name;
        private string _real_name;
        private string _delegate_target_name;
+       private bool? _cpp;
+       private bool? _camelcase;
 
        private static int dynamic_method_id;
 
@@ -558,6 +590,9 @@ public class Vala.CCodeAttribute : AttributeCache {
                                        return sym.name;
                                }
                        } else if (sym is CreationMethod) {
+                               if (cpp) {
+                                       return CCodeBaseModule.get_ccode_name (sym.parent_symbol);
+                               }
                                var m = (CreationMethod) sym;
                                string infix;
                                if (m.parent_symbol is Struct) {
@@ -582,6 +617,18 @@ public class Vala.CCodeAttribute : AttributeCache {
                                        return "_vala_main";
                                } else if (sym.name.has_prefix ("_")) {
                                        return "_%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (sym.parent_symbol), sym.name.substring (1));
+                               } else if (cpp) {
+                                       string cname;
+                                       if (!camelcase) {
+                                               cname = sym.name;
+                                       } else {
+                                               cname = Symbol.lower_case_to_camel_case (sym.name, false);
+                                       }
+                                       if (m.binding == MemberBinding.INSTANCE) {
+                                               return cname;
+                                       } else {
+                                               return "%s%s".printf (CCodeBaseModule.get_ccode_prefix (sym.parent_symbol), cname);
+                                       }
                                } else {
                                        return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (sym.parent_symbol), sym.name);
                                }
@@ -589,17 +636,44 @@ public class Vala.CCodeAttribute : AttributeCache {
                                var acc = (PropertyAccessor) sym;
                                var t = (TypeSymbol) acc.prop.parent_symbol;
 
-                               if (acc.readable) {
-                                       return "%sget_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (t), acc.prop.name);
+                               string cname = acc.readable ? "get" : "set";
+                               if (!camelcase) {
+                                       cname += "_%s".printf (acc.prop.name);
                                } else {
-                                       return "%sset_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (t), acc.prop.name);
+                                       cname += "%s".printf (Symbol.lower_case_to_camel_case (acc.prop.name, true));
+                               }
+
+                               if (cpp) {
+                                       if (acc.prop.binding == MemberBinding.INSTANCE) {
+                                               return cname;
+                                       } else {
+                                               return "%s%s".printf (CCodeBaseModule.get_ccode_prefix (t), cname);
+                                       }
+                               } else {
+                                       return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (t), cname);
                                }
                        } else if (sym is Signal) {
                                return Symbol.camel_case_to_lower_case (sym.name);
                        } else if (sym is LocalVariable || sym is Parameter) {
                                return sym.name;
                        } else {
-                               return "%s%s".printf (CCodeBaseModule.get_ccode_prefix (sym.parent_symbol), sym.name);
+                               var cname = "%s%s".printf (CCodeBaseModule.get_ccode_prefix (sym.parent_symbol), sym.name);
+                               var t = sym as ObjectTypeSymbol;
+                               if (t != null && cpp && t.get_type_parameters().size > 0) {
+                                       cname += "<";
+                                       var first = true;
+                                       var size = t.get_type_parameters().size;
+                                       for (int i=1; i <= size; i++) {
+                                               if (!first) {
+                                                       cname += ",";
+                                               } else {
+                                                       first = false;
+                                               }
+                                               cname += "$%d".printf (i);
+                                       }
+                                       cname += ">";
+                               }
+                               return cname;
                        }
                } else if (node is ObjectType) {
                        var type = (ObjectType) node;
@@ -615,6 +689,12 @@ public class Vala.CCodeAttribute : AttributeCache {
                        } else {
                                cname = CCodeBaseModule.get_ccode_name (type.type_symbol);
                        }
+                       if (CCodeBaseModule.get_ccode_cpp (type.data_type)) {
+                               var i = 1;
+                               foreach (var type_arg in type.get_type_arguments ()) {
+                                       cname = cname.replace ("$%d".printf (i), CCodeBaseModule.get_ccode_name (type_arg));
+                               }
+                       }
                        return "%s*".printf (cname);
                } else if (node is ArrayType) {
                        var type = (ArrayType) node;
@@ -705,8 +785,12 @@ public class Vala.CCodeAttribute : AttributeCache {
        }
 
        private string get_default_prefix () {
-               if (sym is ObjectTypeSymbol) {
-                       return name;
+               if (sym is ObjectTypeSymbol || sym is Struct) {
+                       if (cpp) {
+                               return "%s::".printf (name);
+                       } else {
+                               return name;
+                       }
                } else if (sym is Enum || sym is ErrorDomain) {
                        return "%s_".printf (CCodeBaseModule.get_ccode_upper_case_name (sym));
                } else if (sym is Namespace) {
@@ -715,7 +799,11 @@ public class Vala.CCodeAttribute : AttributeCache {
                                if (sym.parent_symbol != null) {
                                        parent_prefix = CCodeBaseModule.get_ccode_prefix (sym.parent_symbol);
                                }
-                               return "%s%s".printf (parent_prefix, sym.name);
+                               if (cpp) {
+                                       return "%s%s::".printf (parent_prefix, sym.name);
+                               } else {
+                                       return "%s%s".printf (parent_prefix, sym.name);
+                               }
                        } else {
                                return "";
                        }
index 866e8b9e278c90a3fe4014e8c586b81a33810081..876bbe9a81b9083f82bc8c4bbeeff098798df297 100644 (file)
@@ -324,6 +324,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        public bool requires_array_free;
        public bool requires_array_move;
        public bool requires_array_length;
+       public bool requires_cpp_symbols;
 
        public Set<string> wrappers;
        Set<Symbol> generated_external_symbols;
@@ -667,6 +668,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                requires_array_free = false;
                requires_array_move = false;
                requires_array_length = false;
+               requires_cpp_symbols = false;
 
                wrappers = new HashSet<string> (str_hash, str_equal);
                generated_external_symbols = new HashSet<Symbol> ();
@@ -701,6 +703,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                if (requires_array_length) {
                        append_vala_array_length ();
                }
+               if (requires_cpp_symbols) {
+                       source_file.output_filename_extension = ".cpp";
+               }
 
                if (gvaluecollector_h_needed) {
                        cfile.add_include ("gobject/gvaluecollector.h");
@@ -714,8 +719,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        }
                }
 
-               if (!cfile.store (source_file.get_csource_filename (), source_file.filename, context.version_header, context.debug)) {
-                       Report.error (null, "unable to open `%s' for writing".printf (source_file.get_csource_filename ()));
+               if (!cfile.store (source_file.get_output_filename (), source_file.filename, context.version_header, context.debug)) {
+                       Report.error (null, "unable to open `%s' for writing".printf (source_file.get_output_filename ()));
                }
 
                cfile = null;
@@ -2154,7 +2159,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                var st = variable.variable_type.data_type as Struct;
                var creation = expr as ObjectCreationExpression;
                if (creation != null && st != null && (!st.is_simple_type () || get_ccode_name (st) == "va_list") && !variable.variable_type.nullable &&
-                   variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0) {
+                   variable.variable_type.data_type != gvalue_type && creation.get_object_initializer ().size == 0 && !get_ccode_cpp (st)) {
                        return true;
                } else {
                        return false;
@@ -2191,7 +2196,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                                // try to initialize uninitialized variables
                                // initialization not necessary for variables stored in closure
-                               if (rhs == null || is_simple_struct_creation (local, local.initializer)) {
+                               if (rhs == null || is_simple_struct_creation (local, local.initializer) || (local.variable_type.data_type != null && get_ccode_cpp (local.variable_type.data_type))) {
                                        cvar.initializer = default_value_for_type (local.variable_type, true);
                                        cvar.init0 = true;
                                }
@@ -2252,6 +2257,10 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        public TargetValue create_temp_value (DataType type, bool init, CodeNode node_reference, bool? value_owned = null) {
                var local = new LocalVariable (type.copy (), "_tmp%d_".printf (next_temp_var_id++), null, node_reference.source_reference);
                local.no_init = !init;
+               if (type.data_type is Struct && get_ccode_cpp (type.data_type)) {
+                       // C++ structs must be initialized to zero
+                       local.no_init = false;
+               }
                if (value_owned != null) {
                        local.variable_type.value_owned = value_owned;
                }
@@ -2878,7 +2887,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
 
@@ -4307,15 +4316,28 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                        var cl = expr.type_reference.data_type as Class;
 
-                       if (!get_ccode_has_new_function (m)) {
+                       if (get_ccode_cpp (m)) {
+                               requires_cpp_symbols = true;
+                       }
+
+                       if (!get_ccode_has_new_function (m) && !get_ccode_cpp (m)) {
                                // use construct function directly
                                creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
                                creation_call.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
                        } else {
-                               creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
+                               if (st == null && get_ccode_cpp (m)) {
+                                       // C++ doesn't want the final *
+                                       var cpp_name = get_ccode_name (expr.type_reference);
+                                       if (cpp_name.has_suffix ("*")) {
+                                               cpp_name.data[cpp_name.length-1] = '\0';
+                                       }
+                                       creation_call = new CppObjectCreation (new CCodeIdentifier (cpp_name));
+                               } else {
+                                       creation_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
+                               }
                        }
 
-                       if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0)) {
+                       if ((st != null && !st.is_simple_type ()) && !(get_ccode_instance_pos (m) < 0) && !get_ccode_cpp (st)) {
                                creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
                        } else if (st != null && get_ccode_name (st) == "va_list") {
                                creation_call.add_argument (instance);
@@ -4445,7 +4467,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                last_pos = min_pos;
                        }
 
-                       if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0) {
+                       if ((st != null && !st.is_simple_type ()) && get_ccode_instance_pos (m) < 0 && !get_ccode_cpp (st)) {
                                // instance parameter is at the end in a struct creation method
                                creation_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, instance));
                        }
@@ -4502,7 +4524,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        ccode.add_expression (creation_expr);
                        set_cvalue (expr, instance);
                } else if (instance != null) {
-                       if (expr.type_reference.data_type is Struct) {
+                       if (expr.type_reference.data_type is Struct && !get_ccode_cpp (expr.type_reference.data_type)) {
                                ccode.add_expression (creation_expr);
                        } else {
                                ccode.add_assignment (instance, creation_expr);
@@ -4538,6 +4560,11 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        }
 
        public CCodeExpression? handle_struct_argument (Parameter? param, Expression arg, CCodeExpression? cexpr) {
+               if (param != null && get_byref (param)) {
+                       // no need for address of expression
+                       return cexpr;
+               }
+
                DataType type;
                if (param != null) {
                        type = param.variable_type;
@@ -4579,6 +4606,15 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
        public override void visit_unary_expression (UnaryExpression expr) {
                if (expr.operator == UnaryOperator.REF || expr.operator == UnaryOperator.OUT) {
+                       if (expr.formal_target_type != null) {
+                               var param = expr.formal_target_type.parent_node as Parameter;
+                               if (param != null && get_byref (param)) {
+                                       // no need for address of expression
+                                       expr.target_value = expr.inner.target_value;
+                                       return;
+                               }
+                       }
+
                        var glib_value = (GLibValue) expr.inner.target_value;
 
                        var ref_value = new GLibValue (glib_value.value_type);
@@ -5597,9 +5633,14 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                   (st != null || (array_type != null && array_type.fixed_length))) {
                        // 0-initialize struct with struct initializer { 0 }
                        // only allowed as initializer expression in C
-                       var clist = new CCodeInitializerList ();
-                       clist.append (new CCodeConstant ("0"));
-                       return clist;
+                       if (st != null && get_ccode_cpp (st)) {
+                               // c++ will call the default constructor if any
+                               return null;
+                       } else {
+                               var clist = new CCodeInitializerList ();
+                               clist.append (new CCodeConstant ("0"));
+                               return clist;
+                       }
                } else if ((type.data_type != null && type.data_type.is_reference_type ())
                           || type.nullable
                           || type is PointerType || type is DelegateType
@@ -6008,6 +6049,18 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                return "";
        }
 
+       public static bool get_ccode_cpp (Symbol sym) {
+               return get_ccode_attribute(sym).cpp;
+       }
+
+       public static bool get_ccode_camelcase (Symbol sym) {
+               return get_ccode_attribute(sym).camelcase;
+       }
+
+       public static bool get_byref (Symbol sym) {
+               return sym.get_attribute ("ByRef") != null;
+       }
+
        public CCodeConstant get_signal_canonical_constant (Signal sig, string? detail = null) {
                var str = new StringBuilder ("\"");
 
index 09ab3d619501e2aed1b08b971bb726836562f9bf..4bcdfecbc792aa17e31f0c89eeb6f77d585d7e2c 100644 (file)
@@ -43,7 +43,7 @@ public class Vala.CCodeCompiler {
        }
 
        /**
-        * Compile generated C code to object code and optionally link object
+        * Compile generated C/C++ code to object code and optionally link object
         * files.
         *
         * @param context a code context
@@ -106,7 +106,7 @@ public class Vala.CCodeCompiler {
                var source_files = context.get_source_files ();
                foreach (SourceFile file in source_files) {
                        if (file.file_type == SourceFileType.SOURCE) {
-                               cmdline += " " + Shell.quote (file.get_csource_filename ());
+                               cmdline += " " + Shell.quote (file.get_output_filename ());
                        }
                }
                var c_source_files = context.get_c_source_files ();
@@ -135,11 +135,11 @@ public class Vala.CCodeCompiler {
                        Report.error (null, e.message);
                }
 
-               /* remove generated C source and header files */
+               /* remove generated C/C++ source and header files */
                foreach (SourceFile file in source_files) {
                        if (file.file_type == SourceFileType.SOURCE) {
                                if (!context.save_csources) {
-                                       FileUtils.unlink (file.get_csource_filename ());
+                                       FileUtils.unlink (file.get_output_filename ());
                                }
                        }
                }
index 09b8ad7448949391ee62436e96c65eaca3afeada..7de939dfd6eaaf2058dd32765013c4748c615cb4 100644 (file)
@@ -203,16 +203,21 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
                                var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname));
 
                                if (prop.binding == MemberBinding.INSTANCE) {
-                                       if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
-                                               // we need to pass struct instance by reference
-                                               var instance = expr.inner.target_value;
-                                               if (!get_lvalue (instance)) {
-                                                       instance = store_temp_value (instance, expr);
+                                       if (!get_ccode_cpp (prop.get_accessor)) {
+                                               if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
+                                                       // we need to pass struct instance by reference
+                                                       var instance = expr.inner.target_value;
+                                                       if (!get_lvalue (instance)) {
+                                                               instance = store_temp_value (instance, expr);
+                                                       }
+                                                       pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
                                                }
-                                               pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
-                                       }
 
-                                       ccall.add_argument (pub_inst);
+                                               ccall.add_argument (pub_inst);
+                                       } else {
+                                               requires_cpp_symbols = true;
+                                               ccall.call = new CCodeMemberAccess (pub_inst, get_ccode_name (prop.get_accessor), !(prop.parent_symbol is Struct));
+                                       }
                                }
 
                                var temp_value = create_temp_value (prop.get_accessor.value_type, false, expr);
@@ -221,7 +226,7 @@ public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
 
                                // Property access to real struct types is handled differently
                                // The value is returned by out parameter
-                               if (prop.property_type.is_real_non_null_struct_type ()) {
+                               if (prop.property_type.is_real_non_null_struct_type () && !get_byref (prop)) {
                                        ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
                                        ccode.add_expression (ccall);
                                } else {
index fa3f727f6f39081ea9c4faa77c581bcd7d08baa0..fb760d4a10f7afce0e76a2c2afcbc50d53320532 100644 (file)
@@ -193,7 +193,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                        instance = get_cvalue_ (instance_value);
 
                        var st = m.parent_symbol as Struct;
-                       if (st != null && !st.is_simple_type ()) {
+                       if (st != null && !st.is_simple_type () && !get_ccode_cpp (st)) {
                                // we need to pass struct instance by reference
                                if (!get_lvalue (instance_value)) {
                                        instance_value = store_temp_value (instance_value, expr);
@@ -201,8 +201,13 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
                        }
 
-                       in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
-                       out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
+                       if (get_ccode_cpp (m)) {
+                               requires_cpp_symbols = true;
+                               ccall.call = new CCodeMemberAccess (instance, get_ccode_name (m), st == null);
+                       } else {
+                               in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
+                               out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
+                       }
                } else if (m != null && m.binding == MemberBinding.CLASS) {
                        var cl = (Class) m.parent_symbol;
                        var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_upper_case_name (cl, null) + "_CLASS"));
@@ -376,6 +381,9 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                                                        }
                                                                }
                                                        }
+                                               } else if (param.variable_type is ObjectType && get_byref (param)) {
+                                                       // passing an object byref in C++
+                                                       cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, cexpr);
                                                }
 
                                                cexpr = handle_struct_argument (param, arg, cexpr);
@@ -387,7 +395,10 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                                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));
+                                               cexpr = get_cvalue (arg);
+                                               if (!get_byref (param)) {
+                                                       cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, cexpr);
+                                               }
 
                                                if (get_ccode_array_length (param) && param.variable_type is ArrayType) {
                                                        var array_type = (ArrayType) param.variable_type;
@@ -603,7 +614,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                }
 
                // structs are returned via out parameter
-               bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
+               bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type () && (m == null || !get_byref (m));
 
                // pass address for the return value of non-void signals without emitter functions
                if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
@@ -752,6 +763,10 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                        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);
+                               if (result_type is ObjectType && m != null && get_byref (m)) {
+                                       // return object byref in C++
+                                       temp_ref = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, temp_ref);
+                               }
 
                                emit_temp_var (temp_var);
 
diff --git a/codegen/valacppmodule.vala b/codegen/valacppmodule.vala
new file mode 100644 (file)
index 0000000..b05966d
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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_ccode_wrapper_name (CodeNode node) {
+               return get_ccode_name (node).replace("*", "_").replace (":", "_").replace ("<", "_").replace (">", "_");
+       }
+
+       public override CCodeExpression? get_destroy_func_expression (DataType type, bool is_chainup = false) {
+               var cl = type.data_type as Class;
+               if (cl == null || !get_ccode_cpp (cl)) {
+                       return base.get_destroy_func_expression (type, is_chainup);
+               }
+
+               string destroy_func = "_vala_cpp_%s_free".printf (get_ccode_wrapper_name (type));
+               if (!add_wrapper (destroy_func)) {
+                       // wrapper already defined
+                       return new CCodeIdentifier (destroy_func);
+               }
+
+               requires_cpp_symbols = true;
+
+               var function = new CCodeFunction (destroy_func, "void");
+               function.modifiers = CCodeModifiers.STATIC;
+               function.add_parameter (new CCodeParameter ("self", get_ccode_name (type)));
+
+               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);
+       }
+}
index bb85873a7453881686246bea77bec115d4922120..5a289a54c16df152871180d0640dae0ba8037069 100644 (file)
@@ -342,9 +342,9 @@ public abstract class Vala.DovaBaseModule : CodeGenerator {
 
        public override void visit_source_file (SourceFile source_file) {
                if (csource_filename == null) {
-                       csource_filename = source_file.get_csource_filename ();
+                       csource_filename = source_file.get_output_filename ();
                } else {
-                       var writer = new CCodeWriter (source_file.get_csource_filename ());
+                       var writer = new CCodeWriter (source_file.get_output_filename ());
                        if (!writer.open (context.version_header)) {
                                Report.error (null, "unable to open `%s' for writing".printf (writer.filename));
                                return;
index 23d11a3137ffe0269e774e1e005988668a91d170..3047ad4389c852e8b6fdeee6c9d9f1015f102e2d 100644 (file)
@@ -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;
index b0a3fd812b9d96f74ed4cbee186b59c5fec8ba96..8efc5bcbaf4cba624849c1f6972a9ece8b5f0068 100644 (file)
@@ -258,9 +258,9 @@ public class Vala.CodeContext {
        }
 
        /**
-        * Returns a copy of the list of C source files.
+        * Returns a copy of the list of C/C++ source files.
         *
-        * @return list of C source files
+        * @return list of C/C++ source files
         */
        public List<string> get_c_source_files () {
                return c_source_files;
@@ -276,9 +276,9 @@ public class Vala.CodeContext {
        }
 
        /**
-        * Adds the specified file to the list of C source files.
+        * Adds the specified file to the list of C/C++ source files.
         *
-        * @param file a C source file
+        * @param file a C/C++ source file
         */
        public void add_c_source_file (string file) {
                c_source_files.add (file);
@@ -425,7 +425,7 @@ public class Vala.CodeContext {
                        source_file.relative_filename = filename;
 
                        add_source_file (source_file);
-               } else if (filename.has_suffix (".c")) {
+               } else if (filename.has_suffix (".c") || filename.has_suffix (".cpp")) {
                        add_c_source_file (rpath);
                } else {
                        Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.".printf (filename));
index e925a6ba2b152ac0a9107e5eafc7770c9b468eef..9c8b760bdca6171333fef3ab8a7f731df6429626 100644 (file)
@@ -37,6 +37,11 @@ public class Vala.SourceFile {
                }
        }
 
+       /**
+        * The filename extension used for the generated output file.
+        */
+       public string output_filename_extension { get; set; default = ".c"; }
+
        /**
         * Specifies whether this file is a VAPI package file.
         */
@@ -86,7 +91,7 @@ public class Vala.SourceFile {
 
        string? _relative_filename;
 
-       private string csource_filename = null;
+       private string output_filename = null;
        private string cinclude_filename = null;
 
        private ArrayList<string> source_array = null;
@@ -212,22 +217,22 @@ public class Vala.SourceFile {
        }
 
        /**
-        * Returns the filename to use when generating C source files.
+        * Returns the filename to use when generating the output file.
         *
-        * @return generated C source filename
+        * @return generated output filename
         */
-       public string get_csource_filename () {
-               if (csource_filename == null) {
+       public string get_output_filename () {
+               if (output_filename == null) {
                        if (context.run_output) {
-                               csource_filename = context.output + ".c";
+                               output_filename = context.output + output_filename_extension;
                        } else if (context.ccode_only || context.save_csources) {
-                               csource_filename = Path.build_path ("/", get_destination_directory (), get_basename () + ".c");
+                               output_filename = Path.build_path ("/", get_destination_directory (), get_basename () + output_filename_extension);
                        } else {
                                // temporary file
-                               csource_filename = Path.build_path ("/", get_destination_directory (), get_basename () + ".vala.c");
+                               output_filename = Path.build_path ("/", get_destination_directory (), get_basename () + ".vala" + output_filename_extension);
                        }
                }
-               return csource_filename;
+               return output_filename;
        }
 
        /**
index cc92116966c768570d5ef173108b2fa77a617c0c..ecb076c6c7ab49d6eee2349203cfe15c2cb634cb 100644 (file)
@@ -316,12 +316,12 @@ public abstract class Vala.Symbol : CodeNode {
         * @param lower_case a string in lower case
         * @return           the specified string converted to camel case
         */
-       public static string lower_case_to_camel_case (string lower_case) {
+       public static string lower_case_to_camel_case (string lower_case, bool first_uppercase = true) {
                var result_builder = new StringBuilder ("");
 
                weak string i = lower_case;
 
-               bool last_underscore = true;
+               bool last_underscore = first_uppercase;
                while (i.length > 0) {
                        unichar c = i.get_char ();
                        if (c == '_') {