From 3afbe1318cfaa7cb333b420503ec3655adde9edb Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Sat, 31 Mar 2012 22:56:00 +0200 Subject: codegen: Add basic support for using C++ libraries --- ccode/Makefile.am | 2 + ccode/valacppdeletestatement.vala | 47 ++++++++++++++ ccode/valacppobjectcreation.vala | 38 ++++++++++++ codegen/Makefile.am | 1 + codegen/valaccodeattribute.vala | 102 ++++++++++++++++++++++++++++--- codegen/valaccodebasemodule.vala | 79 ++++++++++++++++++++---- codegen/valaccodecompiler.vala | 8 +-- codegen/valaccodememberaccessmodule.vala | 23 ++++--- codegen/valaccodemethodcallmodule.vala | 25 ++++++-- codegen/valacppmodule.vala | 58 ++++++++++++++++++ codegen/valadovabasemodule.vala | 4 +- codegen/valagerrormodule.vala | 2 +- vala/valacodecontext.vala | 10 +-- vala/valasourcefile.vala | 23 ++++--- vala/valasymbol.vala | 4 +- 15 files changed, 369 insertions(+), 57 deletions(-) create mode 100644 ccode/valacppdeletestatement.vala create mode 100644 ccode/valacppobjectcreation.vala create mode 100644 codegen/valacppmodule.vala diff --git a/ccode/Makefile.am b/ccode/Makefile.am index c63dd06e0..fbf81dfde 100644 --- a/ccode/Makefile.am +++ b/ccode/Makefile.am @@ -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 index 000000000..ba629643c --- /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 + */ + +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 index 000000000..47e33b81c --- /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 + */ + +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 2535a88de..dbf558f89 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/valaccodeattribute.vala b/codegen/valaccodeattribute.vala index f22598b76..1113a3220 100644 --- a/codegen/valaccodeattribute.vala +++ b/codegen/valaccodeattribute.vala @@ -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 ""; } diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 866e8b9e2..876bbe9a8 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -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 wrappers; Set 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 (str_hash, str_equal); generated_external_symbols = new HashSet (); @@ -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 ("\""); diff --git a/codegen/valaccodecompiler.vala b/codegen/valaccodecompiler.vala index 09ab3d619..4bcdfecbc 100644 --- a/codegen/valaccodecompiler.vala +++ b/codegen/valaccodecompiler.vala @@ -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 ()); } } } diff --git a/codegen/valaccodememberaccessmodule.vala b/codegen/valaccodememberaccessmodule.vala index 09b8ad744..7de939dfd 100644 --- a/codegen/valaccodememberaccessmodule.vala +++ b/codegen/valaccodememberaccessmodule.vala @@ -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 { diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index fa3f727f6..fb760d4a1 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -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 index 000000000..b05966d99 --- /dev/null +++ b/codegen/valacppmodule.vala @@ -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 + */ + + +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); + } +} diff --git a/codegen/valadovabasemodule.vala b/codegen/valadovabasemodule.vala index bb85873a7..5a289a54c 100644 --- a/codegen/valadovabasemodule.vala +++ b/codegen/valadovabasemodule.vala @@ -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; diff --git a/codegen/valagerrormodule.vala b/codegen/valagerrormodule.vala index 23d11a313..3047ad438 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; diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala index b0a3fd812..8efc5bcba 100644 --- a/vala/valacodecontext.vala +++ b/vala/valacodecontext.vala @@ -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 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)); diff --git a/vala/valasourcefile.vala b/vala/valasourcefile.vala index e925a6ba2..9c8b760bd 100644 --- a/vala/valasourcefile.vala +++ b/vala/valasourcefile.vala @@ -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 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; } /** diff --git a/vala/valasymbol.vala b/vala/valasymbol.vala index cc9211696..ecb076c6c 100644 --- a/vala/valasymbol.vala +++ b/vala/valasymbol.vala @@ -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 == '_') { -- cgit v1.2.1