[vala/wip/issue/128: 46/46] WIP Add further support for params arrays



commit 5000eb93f44522a64871f2e196f8ff0dd65e6bcc
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Wed Sep 11 12:12:49 2019 +0200

    WIP Add further support for params arrays
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/128

 codegen/valaccodearraymodule.vala            | 54 +++++++++++++++++++++++++++-
 codegen/valaccodebasemodule.vala             | 11 +++---
 codegen/valaccodemethodmodule.vala           | 46 +++++++++++++++++++-----
 codegen/valagirwriter.vala                   |  4 +--
 tests/Makefile.am                            |  2 ++
 tests/asynchronous/params-array-invalid.test |  7 ++++
 tests/methods/params-array.vala              | 42 ++++++++++++++++++++++
 vala/valamethod.vala                         | 16 ++++++++-
 vala/valamethodcall.vala                     |  2 +-
 vala/valascope.vala                          |  4 +++
 10 files changed, 171 insertions(+), 17 deletions(-)
---
diff --git a/codegen/valaccodearraymodule.vala b/codegen/valaccodearraymodule.vala
index 607deda3c..f5079bf9a 100644
--- a/codegen/valaccodearraymodule.vala
+++ b/codegen/valaccodearraymodule.vala
@@ -780,7 +780,7 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
        }
 
        public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, 
Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
-               if (!(param.variable_type is ArrayType)) {
+               if (param.params_array || !(param.variable_type is ArrayType)) {
                        return base.generate_parameter (param, decl_space, cparam_map, carg_map);
                }
 
@@ -822,4 +822,56 @@ public class Vala.CCodeArrayModule : CCodeMethodCallModule {
 
                return main_cparam;
        }
+
+       public override void append_params_array (LocalVariable local) {
+               var type = (ArrayType) local.variable_type;
+
+               var local_length = new LocalVariable (type.length_type.copy (), get_array_length_cname 
(local.name, 1), null, local.source_reference);
+               var local_size = new LocalVariable (type.length_type.copy (), get_array_size_cname 
(get_local_cname (local)));
+
+               var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+               gnew.add_argument (new CCodeIdentifier (get_ccode_name (type.element_type)));
+
+               CCodeExpression length_expr = get_local_cexpression (local_length);
+               // add extra item to have array NULL-terminated for all reference types
+               if (type.element_type.type_symbol != null && type.element_type.type_symbol.is_reference_type 
()) {
+                       length_expr = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, length_expr, new 
CCodeConstant ("1"));
+               }
+               gnew.add_argument (length_expr);
+               ccode.add_assignment (get_local_cexpression (local), gnew);
+
+               //FIXME handle struct elements correcly
+               var element = new LocalVariable (type.element_type.copy (), "_%s_element".printf 
(get_ccode_name (local)), null, local.source_reference);
+               emit_temp_var (element);
+
+               ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_va_list_%s".printf 
(get_ccode_name (local))));
+               var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
+               va_start.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
+               va_start.add_argument (new CCodeIdentifier ("_first_%s".printf (get_ccode_name (local))));
+               ccode.add_expression (va_start);
+
+               ccode.add_assignment (get_local_cexpression (element), new CCodeIdentifier 
("_first_%s".printf (get_ccode_name (local))));
+               ccode.open_while (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, 
get_local_cexpression (element), new CCodeConstant ("NULL")));
+
+               var va_arg = new CCodeFunctionCall (new CCodeIdentifier ("va_arg"));
+               va_arg.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
+               va_arg.add_argument (new CCodeIdentifier (get_ccode_name (type.element_type)));
+
+               var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_array_add_wrapper (type)));
+               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
get_local_cexpression (local)));
+               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
get_local_cexpression (local_length)));
+               ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
get_local_cexpression (local_size)));
+               //FIXME handle struct elements correcly
+               ccall.add_argument (get_local_cexpression (element));
+               //ccall.add_argument (handle_struct_argument (value_param, element, get_cvalue (element)));
+
+               ccode.add_expression (ccall);
+               ccode.add_assignment (get_local_cexpression (element), va_arg);
+
+               ccode.close ();
+
+               var va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
+               va_end.add_argument (new CCodeIdentifier ("_va_list_%s".printf (get_ccode_name (local))));
+               ccode.add_expression (va_end);
+       }
 }
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 873f1ad34..4282a1ac5 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -727,6 +727,9 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        public virtual void append_vala_array_length () {
        }
 
+       public virtual void append_params_array (LocalVariable local) {
+       }
+
        public void append_vala_clear_mutex (string typename, string funcprefix) {
                // memset
                cfile.add_include ("string.h");
@@ -2339,7 +2342,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                if (!unreachable_exit_block && b.parent_symbol is Method) {
                        var m = (Method) b.parent_symbol;
                        foreach (Parameter param in m.get_parameters ()) {
-                               if (!param.captured && !param.ellipsis && requires_destroy 
(param.variable_type) && param.direction == ParameterDirection.IN) {
+                               if (!param.captured && !param.ellipsis && !param.params_array && 
requires_destroy (param.variable_type) && param.direction == ParameterDirection.IN) {
                                        ccode.add_expression (destroy_parameter (param));
                                } else if (param.direction == ParameterDirection.OUT && !m.coroutine) {
                                        return_out_parameter (param);
@@ -3832,7 +3835,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
        private void append_param_free (Method m) {
                foreach (Parameter param in m.get_parameters ()) {
-                       if (!param.captured && !param.ellipsis && requires_destroy (param.variable_type) && 
param.direction == ParameterDirection.IN) {
+                       if (!param.captured && !param.ellipsis && !param.params_array && requires_destroy 
(param.variable_type) && param.direction == ParameterDirection.IN) {
                                ccode.add_expression (destroy_parameter (param));
                        }
                }
@@ -4721,7 +4724,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                                Parameter last_param = null;
                                                // FIXME: this doesn't take into account exception handling 
parameters
                                                foreach (var param in current_method.get_parameters ()) {
-                                                       if (param.ellipsis) {
+                                                       if (param.ellipsis || param.params_array) {
                                                                break;
                                                        }
                                                        last_param = param;
@@ -4784,7 +4787,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                Parameter param = null;
                                if (params_it.next ()) {
                                        param = params_it.get ();
-                                       ellipsis = param.ellipsis;
+                                       ellipsis = param.ellipsis || param.params_array;
                                        if (!ellipsis) {
                                                if (param.direction == ParameterDirection.OUT) {
                                                        carg_map = out_arg_map;
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 7a4b30394..41d4851f1 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -556,7 +556,10 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                                }
 
                                foreach (Parameter param in m.get_parameters ()) {
-                                       if (param.ellipsis) {
+                                       if (param.ellipsis || param.params_array) {
+                                               if (param.params_array) {
+                                                       append_params_array (m.params_array_var);
+                                               }
                                                break;
                                        }
 
@@ -868,7 +871,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 
        public virtual CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, 
Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
                CCodeParameter cparam;
-               if (!param.ellipsis) {
+               if (!param.ellipsis && !param.params_array) {
                        string ctypename = get_ccode_name (param.variable_type);
 
                        generate_type_declaration (param.variable_type, decl_space);
@@ -895,15 +898,42 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                        if (param.format_arg) {
                                cparam.modifiers = CCodeModifiers.FORMAT_ARG;
                        }
-               } else if (ellipses_to_valist) {
-                       cparam = new CCodeParameter ("_vala_va_list", "va_list");
                } else {
-                       cparam = new CCodeParameter.with_ellipsis ();
+                       // Add _first_* parameter for the params array parameter
+                       if (param.params_array) {
+                               var param_type = ((ArrayType) param.variable_type).element_type;
+                               string ctypename = get_ccode_name (param_type);
+
+                               generate_type_declaration (param_type, decl_space);
+
+                               // pass non-simple structs always by reference
+                               if (param_type.type_symbol is Struct) {
+                                       var st = (Struct) param_type.type_symbol;
+                                       if (!st.is_simple_type () && param.direction == 
ParameterDirection.IN) {
+                                               if (st.is_immutable && !param.variable_type.value_owned) {
+                                                       ctypename = "const " + ctypename;
+                                               }
+
+                                               if (!param_type.nullable) {
+                                                       ctypename += "*";
+                                               }
+                                       }
+                               }
+
+                               cparam = new CCodeParameter ("_first_%s".printf (get_ccode_name (param)), 
ctypename);
+                               cparam_map.set (get_param_pos (get_ccode_pos (param), false), cparam);
+                       }
+
+                       if (ellipses_to_valist) {
+                               cparam = new CCodeParameter ("_vala_va_list", "va_list");
+                       } else {
+                               cparam = new CCodeParameter.with_ellipsis ();
+                       }
                }
 
-               cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), cparam);
-               if (carg_map != null && !param.ellipsis) {
-                       carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis), 
get_parameter_cexpression (param));
+               cparam_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || param.params_array), 
cparam);
+               if (carg_map != null && !param.ellipsis && !param.params_array) {
+                       carg_map.set (get_param_pos (get_ccode_pos (param), param.ellipsis || 
param.params_array), get_parameter_cexpression (param));
                }
 
                return cparam;
diff --git a/codegen/valagirwriter.vala b/codegen/valagirwriter.vala
index d65e8b80c..4067a8c39 100644
--- a/codegen/valagirwriter.vala
+++ b/codegen/valagirwriter.vala
@@ -1114,7 +1114,7 @@ public class Vala.GIRWriter : CodeVisitor {
                        }
 
                        foreach (Parameter param in params) {
-                               write_param_or_return (param.variable_type, true, ref index, 
get_ccode_array_length (param), param.name, get_parameter_comment (param), param.direction, false, false, 
param.ellipsis);
+                               write_param_or_return (param.variable_type, true, ref index, 
get_ccode_array_length (param), param.name, get_parameter_comment (param), param.direction, false, false, 
param.ellipsis || param.params_array);
 
                                write_implicit_params (param.variable_type, ref index, get_ccode_array_length 
(param), param.name, param.direction);
                        }
@@ -1213,7 +1213,7 @@ public class Vala.GIRWriter : CodeVisitor {
                        return false;
                }
                foreach (var param in m.get_parameters ()) {
-                       if (param.ellipsis || !is_type_introspectable (param.variable_type)) {
+                       if (param.ellipsis || param.params_array || !is_type_introspectable 
(param.variable_type)) {
                                return false;
                        }
                }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 292eea0c7..721d4401b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -151,6 +151,7 @@ TESTS = \
        methods/bug791283.vala \
        methods/argument-array-initilizer.vala \
        methods/generics.vala \
+       methods/params-array.vala \
        methods/printf-invalid.test \
        methods/printf-constructor.vala \
        methods/printf-constructor-invalid.test \
@@ -494,6 +495,7 @@ TESTS = \
        asynchronous/finish-name.vala \
        asynchronous/generator.vala \
        asynchronous/out-parameter-invalid.test \
+       asynchronous/params-array-invalid.test \
        asynchronous/result-pos.vala \
        asynchronous/variadic-invalid.test \
        asynchronous/variadic-invalid-2.test \
diff --git a/tests/asynchronous/params-array-invalid.test b/tests/asynchronous/params-array-invalid.test
new file mode 100644
index 000000000..17426647c
--- /dev/null
+++ b/tests/asynchronous/params-array-invalid.test
@@ -0,0 +1,7 @@
+Invalid Code
+
+async void foo (params string[] args) {
+}
+
+void main () {
+}
diff --git a/tests/methods/params-array.vala b/tests/methods/params-array.vala
new file mode 100644
index 000000000..3c76d7048
--- /dev/null
+++ b/tests/methods/params-array.vala
@@ -0,0 +1,42 @@
+void foo (params string[] strv) {
+       assert (strv.length == 3);
+       assert (strv[0] == "foo");
+       assert (strv[1] == "bar");
+       assert (strv[2] == "manam");
+}
+
+void bar (params int[] intv) {
+       assert (intv.length == 3);
+       assert (intv[0] == 23);
+       assert (intv[1] == 42);
+       assert (intv[2] == 4711);
+}
+
+void manam (params Value?[] valuev) {
+       assert (valuev.length == 3);
+       assert (valuev[0] == "foo");
+       assert (valuev[1] == 4711);
+       assert (valuev[2] == 3.1415);
+}
+
+void manam_owned (params owned Value?[] valuev) {
+       assert (valuev.length == 3);
+       assert (valuev[0] == "foo");
+       assert (valuev[1] == 4711);
+       assert (valuev[2] == 3.1415);
+}
+
+void minim (params Variant[] variantv) {
+       assert (variantv.length == 3);
+       assert ((string) variantv[0] == "foo");
+       assert ((int) variantv[1] == 4711);
+       assert ((double) variantv[2] == 3.1415);
+}
+
+void main () {
+       foo ("foo", "bar", "manam");
+       bar (23, 42, 4711);
+       manam ("foo", 4711, 3.1415);
+       manam_owned ("foo", 4711, 3.1415);
+       minim ("foo", 4711, 3.1415);
+}
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 4e288a210..253119713 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -175,6 +175,8 @@ public class Vala.Method : Subroutine, Callable {
                }
        }
 
+       public LocalVariable? params_array_var { get; private set; }
+
        public weak Signal signal_reference { get; set; }
 
        public bool closure { get; set; }
@@ -811,7 +813,7 @@ public class Vala.Method : Subroutine, Callable {
                                error = true;
                                Report.error (param.source_reference, "Reference parameters are not supported 
for async methods");
                        }
-                       if (!external_package && coroutine && (param.ellipsis || 
param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol)) {
+                       if (!external_package && coroutine && (param.ellipsis || param.params_array || 
param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol)) {
                                error = true;
                                Report.error (param.source_reference, "Variadic parameters are not supported 
for async methods");
                                return false;
@@ -825,6 +827,15 @@ public class Vala.Method : Subroutine, Callable {
                        } else if (param.initializer != null) {
                                optional_param = true;
                        }
+
+                       // Add local variable to provide access to params arrays which will be constructed 
out of the given va-args
+                       if (param.params_array && body != null) {
+                               var type = (ArrayType) param.variable_type.copy ();
+                               type.element_type.value_owned = type.value_owned;
+                               type.value_owned = true;
+                               params_array_var = new LocalVariable (type, param.name, null, 
source_reference);
+                               body.insert_statement (0, new DeclarationStatement (params_array_var, 
source_reference));
+                       }
                }
 
                if (coroutine) {
@@ -1213,6 +1224,9 @@ public class Vala.Method : Subroutine, Callable {
                if (result_var != null) {
                        collection.add (result_var);
                }
+               if (params_array_var != null) {
+                       collection.add (params_array_var);
+               }
 
                // capturing variables is only supported if they are initialized
                // therefore assume that captured variables are initialized
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index 9aaa0dd04..6b461d64f 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -450,7 +450,7 @@ public class Vala.MethodCall : Expression {
                                        // recreate iterator and skip to right position
                                        arg_it = argument_list.iterator ();
                                        foreach (Parameter param in params) {
-                                               if (param.ellipsis) {
+                                               if (param.ellipsis || param.params_array) {
                                                        break;
                                                }
                                                arg_it.next ();
diff --git a/vala/valascope.vala b/vala/valascope.vala
index 1a59d24ea..f0f02561b 100644
--- a/vala/valascope.vala
+++ b/vala/valascope.vala
@@ -56,6 +56,10 @@ public class Vala.Scope {
         * @param sym  a symbol
         */
        public void add (string? name, Symbol sym) {
+               // Ignore params-array parameters which can not be conflicted with
+               if (sym is Parameter && ((Parameter) sym).params_array) {
+                       name = null;
+               }
                if (name != null) {
                        if (symbol_table == null) {
                                symbol_table = new HashMap<string,Symbol> (str_hash, str_equal);


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