]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add foreach statement support for GLib.GenericArray
authorCorentin Noël <corentin.noel@collabora.com>
Thu, 15 Oct 2020 08:35:25 +0000 (10:35 +0200)
committerRico Tzschichholz <ricotz@ubuntu.com>
Mon, 3 May 2021 07:11:56 +0000 (09:11 +0200)
It is now possible to use foreach with a GLib.GenericArray type

codegen/valaccodebasemodule.vala
codegen/valaccodecontrolflowmodule.vala
tests/Makefile.am
tests/basic-types/gptrarray.vala
tests/control-flow/foreach.vala
tests/control-flow/gptrarray-foreach-variable.test [new file with mode: 0644]
vala/valaforeachstatement.vala
vala/valasemanticanalyzer.vala

index fc52e7b8cb95800a2d6634cac15b6cbae0cd8b96..aa2a6ac494a21bc70268e55333020aa721868ee1 100644 (file)
@@ -337,7 +337,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        public TypeSymbol gstringbuilder_type;
        public TypeSymbol garray_type;
        public TypeSymbol gbytearray_type;
-       public TypeSymbol gptrarray_type;
+       public TypeSymbol genericarray_type;
        public TypeSymbol gthreadpool_type;
        public DataType gquark_type;
        public Struct gvalue_type;
@@ -510,7 +510,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        gstringbuilder_type = (TypeSymbol) glib_ns.scope.lookup ("StringBuilder");
                        garray_type = (TypeSymbol) glib_ns.scope.lookup ("Array");
                        gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
-                       gptrarray_type = (TypeSymbol) glib_ns.scope.lookup ("PtrArray");
+                       genericarray_type = (TypeSymbol) glib_ns.scope.lookup ("GenericArray");
                        gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
 
                        gerror = (Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Error");
index 5cca19707d4537f82a33b8bb557b9c022c0667a6..bbc53024713fc1d57ba699c55dc165fdc836e3fe 100644 (file)
@@ -308,6 +308,35 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
 
                        stmt.body.emit (this);
 
+                       ccode.close ();
+               } else if (stmt.collection.value_type.compatible (new ObjectType ((Class) genericarray_type))) {
+                       // iterating over a GenericArray / GPtrArray
+
+                       var iterator_variable = new LocalVariable (uint_type.copy (), "%s_index".printf (stmt.variable_name));
+                       visit_local_variable (iterator_variable);
+                       var arr_index = get_variable_cname (get_local_cname (iterator_variable));
+
+                       var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, get_variable_cexpression (arr_index), new CCodeMemberAccess.pointer (get_variable_cexpression (get_local_cname (collection_backup)), "len"));
+
+                       ccode.open_for (new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeConstant ("0")),
+                                          ccond,
+                                          new CCodeAssignment (get_variable_cexpression (arr_index), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, get_variable_cexpression (arr_index), new CCodeConstant ("1"))));
+
+                       var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_ptr_array_index"));
+                       get_item.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
+                       get_item.add_argument (get_variable_cexpression (arr_index));
+
+                       CCodeExpression element_expr = get_item;
+
+                       if (stmt.type_reference.value_owned) {
+                               element_expr = get_cvalue_ (copy_value (new GLibValue (stmt.type_reference, element_expr), stmt.element_variable));
+                       }
+
+                       visit_local_variable (stmt.element_variable);
+                       ccode.add_assignment (get_variable_cexpression (get_local_cname (stmt.element_variable)), element_expr);
+
+                       stmt.body.emit (this);
+
                        ccode.close ();
                } else if (stmt.collection.value_type.compatible (new ObjectType (gvaluearray_type))) {
                        // iterating over a GValueArray
index 64e7101cf90f010894a6e03e8e1834c40ebd0b26..281531d223e9d3835c455aaaa12ef8f250228fc6 100644 (file)
@@ -257,6 +257,7 @@ TESTS = \
        control-flow/for.vala \
        control-flow/for-switch-continue.vala \
        control-flow/foreach.vala \
+       control-flow/gptrarray-foreach-variable.test \
        control-flow/local-clash-with-implicit-this.vala \
        control-flow/missing-break.test \
        control-flow/missing-return.test \
index 6d8aa2d1a3ede10b4393d96c39f98051c2c6d44d..1b5d6c6223e1c275eca94b0cdbb41ceb1b643f93 100644 (file)
@@ -26,6 +26,30 @@ void main () {
                assert (foo3.ref_count == 2);
                assert (array.length == 3);
 
+               int loop_size = 0;
+               foreach (weak Foo element in array) {
+                       loop_size++;
+                       assert (element.ref_count == 2);
+                       switch (loop_size) {
+                               case 1: assert (element == foo1); break;
+                               case 2: assert (element == foo2); break;
+                               case 3: assert (element == foo3); break;
+                       }
+               }
+               assert (loop_size == 3);
+
+               loop_size = 0;
+               foreach (Foo element in array) {
+                       loop_size++;
+                       assert (element.ref_count == 3);
+                       switch (loop_size) {
+                               case 1: assert (element == foo1); break;
+                               case 2: assert (element == foo2); break;
+                               case 3: assert (element == foo3); break;
+                       }
+               }
+               assert (loop_size == 3);
+
                assert (foo2 == array.get (1));
                array.set (1, foo4);
                assert (foo4 == array.get (1));
@@ -73,6 +97,30 @@ void main () {
                assert (foo3.ref_count == 1);
                assert (array.length == 3);
 
+               int loop_size = 0;
+               foreach (weak Foo element in array) {
+                       loop_size++;
+                       assert (element.ref_count == 1);
+                       switch (loop_size) {
+                               case 1: assert (element == foo1); break;
+                               case 2: assert (element == foo2); break;
+                               case 3: assert (element == foo3); break;
+                       }
+               }
+               assert (loop_size == 3);
+
+               loop_size = 0;
+               foreach (Foo element in array) {
+                       loop_size++;
+                       assert (element.ref_count == 2);
+                       switch (loop_size) {
+                               case 1: assert (element == foo1); break;
+                               case 2: assert (element == foo2); break;
+                               case 3: assert (element == foo3); break;
+                       }
+               }
+               assert (loop_size == 3);
+
                assert (foo2 == array.get (1));
                array.set (1, foo4);
                assert (foo4 == array.get (1));
index 6a36453fd9feb720b3004fdc317a9a71c26460db..052e03d3c9aa6734689b9b0535089b0785787ef8 100644 (file)
@@ -33,6 +33,41 @@ void test_foreach_gvaluearray () {
        test_unowned (array);
 }
 
+void test_generic_array_owned (GenericArray<Value?> array) {
+       uint i = 0;
+
+       foreach (Value? item in array) {
+               i++;
+       }
+
+       assert (i == 3);
+}
+
+void test_generic_array_unowned (GenericArray<Value?> array) {
+       uint i = 0;
+
+       foreach (unowned Value? item in array) {
+               i++;
+       }
+
+       assert (i == 3);
+}
+
+void test_foreach_genericarray () {
+       Value value;
+       var array = new GenericArray<Value?> ();
+
+       value = 1;
+       array.add (value);
+       value = 2.0;
+       array.add (value);
+       value = "three";
+       array.add (value);
+
+       test_generic_array_owned (array);
+       test_generic_array_unowned (array);
+}
+
 void test_foreach_multidim_array () {
        int[,] foo = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
        string result = "";
@@ -70,6 +105,7 @@ void test_foreach_slice_array () {
 
 void main () {
        test_foreach_gvaluearray ();
+       test_foreach_genericarray ();
        test_foreach_const_array ();
        test_foreach_multidim_array ();
        test_foreach_slice_array ();
diff --git a/tests/control-flow/gptrarray-foreach-variable.test b/tests/control-flow/gptrarray-foreach-variable.test
new file mode 100644 (file)
index 0000000..3cef848
--- /dev/null
@@ -0,0 +1,7 @@
+Invalid Code
+
+void main () {
+       var array = new GenericArray<string> ();
+       foreach (int element in array) {
+       }
+}
index 0af0b52bad90c5dbe2af1d626da376f81b47a156..d18de773e6d35c421539381f93a543e404e87b05 100644 (file)
@@ -180,7 +180,8 @@ public class Vala.ForeachStatement : Block {
                        array_type.inline_allocated = false;
 
                        return check_without_iterator (context, collection_type, array_type.element_type);
-               } else if (context.profile == Profile.GOBJECT && (collection_type.compatible (context.analyzer.glist_type) || collection_type.compatible (context.analyzer.gslist_type))) {
+               } else if (context.profile == Profile.GOBJECT && (collection_type.compatible (context.analyzer.glist_type)
+                   || collection_type.compatible (context.analyzer.gslist_type) || collection_type.compatible (context.analyzer.genericarray_type))) {
                        if (collection_type.get_type_arguments ().size != 1) {
                                error = true;
                                Report.error (collection.source_reference, "missing type argument for collection");
index 378c301bd332016db745221dd9f3a874aef29965..fa101b6c8c9a73b51c4ca6d762a8bdc9678a7417 100644 (file)
@@ -163,6 +163,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public DataType gslist_type;
        public DataType garray_type;
        public DataType gvaluearray_type;
+       public DataType genericarray_type;
        public Class gerror_type;
        public DataType list_type;
        public DataType tuple_type;
@@ -228,6 +229,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
                        garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
                        gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
+                       genericarray_type = new ObjectType ((Class) glib_ns.scope.lookup ("GenericArray"));
 
                        gerror_type = (Class) glib_ns.scope.lookup ("Error");
                        regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));