[vala/wip/issue/128: 49/49] WIP Add further support for params arrays
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/issue/128: 49/49] WIP Add further support for params arrays
- Date: Tue, 19 Nov 2019 13:08:58 +0000 (UTC)
commit 1e4dc95ce582fee77cd5d3d920a71529c679563f
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 9e836b1d7..668d3cee2 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");
@@ -2342,7 +2345,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);
@@ -3839,7 +3842,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));
}
}
@@ -4728,7 +4731,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;
@@ -4791,7 +4794,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 9eb868015..c2855b53e 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -541,7 +541,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;
}
@@ -847,7 +850,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);
@@ -874,15 +877,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 65fafeada..0198cc908 100644
--- a/codegen/valagirwriter.vala
+++ b/codegen/valagirwriter.vala
@@ -1127,7 +1127,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);
}
@@ -1226,7 +1226,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 9d2e5cc6d..079b90223 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -152,6 +152,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 \
@@ -502,6 +503,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 4af74c759..8e5194f61 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; }
@@ -815,7 +817,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;
@@ -829,6 +831,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) {
@@ -1217,6 +1228,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 1c6e2b404..b9772fed8 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]