]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add foreach statement support for GLib.Sequence
authorPrinceton Ferro <princetonferro@gmail.com>
Tue, 25 Jan 2022 03:32:01 +0000 (22:32 -0500)
committerRico Tzschichholz <ricotz@ubuntu.com>
Tue, 25 Jan 2022 11:25:30 +0000 (12:25 +0100)
It is now possible to use foreach with a GLib.Sequence

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

index ccb2fe988d60294b56eedb0fe6b4b1c09d8f447e..cf0d946822173a5a887b27f2a8eeceba8394e792 100644 (file)
@@ -338,6 +338,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
        public Class garray_type;
        public TypeSymbol gbytearray_type;
        public TypeSymbol genericarray_type;
+       public Class gsequence_type;
+       public Class gsequence_iter_type;
        public TypeSymbol gthreadpool_type;
        public DataType gquark_type;
        public Struct gvalue_type;
@@ -512,6 +514,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                        garray_type = (Class) glib_ns.scope.lookup ("Array");
                        gbytearray_type = (TypeSymbol) glib_ns.scope.lookup ("ByteArray");
                        genericarray_type = (TypeSymbol) glib_ns.scope.lookup ("GenericArray");
+                       gsequence_type = (Class) glib_ns.scope.lookup ("Sequence");
+                       gsequence_iter_type = (Class) glib_ns.scope.lookup ("SequenceIter");
                        gthreadpool_type = (TypeSymbol) glib_ns.scope.lookup ("ThreadPool");
 
                        gerror = (Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Error");
index dc278e4755328c07943154bdf1c2b5a67b330353..ce57da62f1e19d33a018c0bae3ce0a5c2af7b491 100644 (file)
@@ -400,6 +400,38 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
 
                        stmt.body.emit (this);
 
+                       ccode.close ();
+               } else if (stmt.collection.value_type.compatible (new ObjectType (gsequence_type))) {
+                       // iterating over a GSequence
+
+                       var iterator_variable = new LocalVariable (new ObjectType (gsequence_iter_type), "%s_iter".printf (stmt.variable_name));
+                       visit_local_variable (iterator_variable);
+                       var sequence_iter = get_variable_cname (get_local_cname (iterator_variable));
+
+                       var ccond_is_end = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_iter_is_end"));
+                       ccond_is_end.add_argument (get_variable_cexpression (sequence_iter));
+                       var ccond = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccond_is_end);
+                       var cbegin = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_get_begin_iter"));
+                       cbegin.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
+                       var cnext = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_iter_next"));
+                       cnext.add_argument (get_variable_cexpression (sequence_iter));
+
+                       ccode.open_for (new CCodeAssignment (get_variable_cexpression (sequence_iter), cbegin),
+                                       ccond,
+                                       new CCodeAssignment (get_variable_cexpression (sequence_iter), cnext));
+
+                       var get_item = new CCodeFunctionCall (new CCodeIdentifier ("g_sequence_get"));
+                       get_item.add_argument (get_variable_cexpression (sequence_iter));
+
+                       var element_type = collection_type.get_type_arguments ().get (0).copy ();
+                       element_type.value_owned = false;
+                       var element_expr = get_cvalue_ (transform_value (new GLibValue (element_type, get_item, true), stmt.type_reference, stmt));
+
+                       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 {
                        Report.error (stmt.source_reference, "internal error: unsupported collection type");
index b56263e8fbb3ab1115926e175356586f6713ebd9..2103afa6e6025bcedeeda9ddf9e10a7cc7203aee 100644 (file)
@@ -279,6 +279,7 @@ TESTS = \
        control-flow/foreach.vala \
        control-flow/garray-foreach-variable.test \
        control-flow/gptrarray-foreach-variable.test \
+       control-flow/gsequence-foreach-variable.test \
        control-flow/local-clash-with-implicit-this.vala \
        control-flow/missing-break.test \
        control-flow/missing-return.test \
index c7d2e6da111395389bf34843ea1491773281ed0a..23225a44362d21c8be487529d6f1180c0c7a6bd1 100644 (file)
@@ -19,6 +19,7 @@
 #define _g_value_array_free0(var) ((var == NULL) ? NULL : (var = (g_value_array_free (var), NULL)))
 #define __vala_GValue_free0(var) ((var == NULL) ? NULL : (var = (_vala_GValue_free (var), NULL)))
 #define _g_ptr_array_unref0(var) ((var == NULL) ? NULL : (var = (g_ptr_array_unref (var), NULL)))
+#define _g_sequence_free0(var) ((var == NULL) ? NULL : (var = (g_sequence_free (var), NULL)))
 #define _g_array_unref0(var) ((var == NULL) ? NULL : (var = (g_array_unref (var), NULL)))
 #define _g_free0(var) (var = (g_free (var), NULL))
 #define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
@@ -35,6 +36,9 @@ static void _vala_GValue_free (GValue* self);
 VALA_EXTERN void test_generic_array_unowned (GPtrArray* array);
 VALA_EXTERN void test_foreach_genericarray (void);
 static void __vala_GValue_free0_ (gpointer var);
+VALA_EXTERN void test_gsequence_owned (GSequence* sequence);
+VALA_EXTERN void test_gsequence_unowned (GSequence* sequence);
+VALA_EXTERN void test_foreach_gsequence (void);
 VALA_EXTERN void test_garray_owned (GArray* array);
 VALA_EXTERN void test_garray_unowned (GArray* array);
 VALA_EXTERN void test_foreach_garray (void);
@@ -264,6 +268,108 @@ test_foreach_genericarray (void)
        G_IS_VALUE (&value) ? (g_value_unset (&value), NULL) : NULL;
 }
 
+void
+test_gsequence_owned (GSequence* sequence)
+{
+       guint i = 0U;
+       g_return_if_fail (sequence != NULL);
+       i = (guint) 0;
+       {
+               GSequence* item_collection = NULL;
+               GSequenceIter* item_iter = NULL;
+               item_collection = sequence;
+               for (item_iter = g_sequence_get_begin_iter (item_collection); !g_sequence_iter_is_end (item_iter); item_iter = g_sequence_iter_next (item_iter)) {
+                       GValue* _tmp0_;
+                       GValue* item = NULL;
+                       _tmp0_ = __g_value_dup0 (g_sequence_get (item_iter));
+                       item = _tmp0_;
+                       {
+                               guint _tmp1_;
+                               _tmp1_ = i;
+                               i = _tmp1_ + 1;
+                               __vala_GValue_free0 (item);
+                       }
+               }
+       }
+       _vala_assert (i == ((guint) 3), "i == 3");
+}
+
+void
+test_gsequence_unowned (GSequence* sequence)
+{
+       guint i = 0U;
+       g_return_if_fail (sequence != NULL);
+       i = (guint) 0;
+       {
+               GSequence* item_collection = NULL;
+               GSequenceIter* item_iter = NULL;
+               item_collection = sequence;
+               for (item_iter = g_sequence_get_begin_iter (item_collection); !g_sequence_iter_is_end (item_iter); item_iter = g_sequence_iter_next (item_iter)) {
+                       GValue* item = NULL;
+                       item = g_sequence_get (item_iter);
+                       {
+                               guint _tmp0_;
+                               _tmp0_ = i;
+                               i = _tmp0_ + 1;
+                       }
+               }
+       }
+       _vala_assert (i == ((guint) 3), "i == 3");
+}
+
+void
+test_foreach_gsequence (void)
+{
+       GValue value = {0};
+       GSequence* sequence = NULL;
+       GSequence* _tmp0_;
+       GValue _tmp1_ = {0};
+       GValue _tmp2_;
+       GValue _tmp3_;
+       GValue* _tmp4_;
+       GSequenceIter* _tmp5_;
+       GValue _tmp6_ = {0};
+       GValue _tmp7_;
+       GValue _tmp8_;
+       GValue* _tmp9_;
+       GSequenceIter* _tmp10_;
+       GValue _tmp11_ = {0};
+       GValue _tmp12_;
+       GValue _tmp13_;
+       GValue* _tmp14_;
+       GSequenceIter* _tmp15_;
+       _tmp0_ = g_sequence_new (__vala_GValue_free0_);
+       sequence = _tmp0_;
+       g_value_init (&_tmp1_, G_TYPE_INT);
+       g_value_set_int (&_tmp1_, 1);
+       G_IS_VALUE (&value) ? (g_value_unset (&value), NULL) : NULL;
+       value = _tmp1_;
+       _tmp2_ = value;
+       _tmp3_ = _tmp2_;
+       _tmp4_ = __g_value_dup0 (&_tmp3_);
+       _tmp5_ = g_sequence_append (sequence, _tmp4_);
+       g_value_init (&_tmp6_, G_TYPE_DOUBLE);
+       g_value_set_double (&_tmp6_, 2.0);
+       G_IS_VALUE (&value) ? (g_value_unset (&value), NULL) : NULL;
+       value = _tmp6_;
+       _tmp7_ = value;
+       _tmp8_ = _tmp7_;
+       _tmp9_ = __g_value_dup0 (&_tmp8_);
+       _tmp10_ = g_sequence_append (sequence, _tmp9_);
+       g_value_init (&_tmp11_, G_TYPE_STRING);
+       g_value_set_string (&_tmp11_, "three");
+       G_IS_VALUE (&value) ? (g_value_unset (&value), NULL) : NULL;
+       value = _tmp11_;
+       _tmp12_ = value;
+       _tmp13_ = _tmp12_;
+       _tmp14_ = __g_value_dup0 (&_tmp13_);
+       _tmp15_ = g_sequence_append (sequence, _tmp14_);
+       test_gsequence_owned (sequence);
+       test_gsequence_unowned (sequence);
+       _g_sequence_free0 (sequence);
+       G_IS_VALUE (&value) ? (g_value_unset (&value), NULL) : NULL;
+}
+
 void
 test_garray_owned (GArray* array)
 {
@@ -569,6 +675,7 @@ _vala_main (void)
        test_foreach_gvaluearray ();
        test_foreach_garray ();
        test_foreach_genericarray ();
+       test_foreach_gsequence ();
        test_foreach_const_array ();
        test_foreach_multidim_array ();
        test_foreach_slice_array ();
index a0a01a865a5de4966014fbf8294d3ff4e120ff39..8689a18ad9c70d03b589f0e5198b513690fcbfe8 100644 (file)
@@ -68,6 +68,41 @@ void test_foreach_genericarray () {
        test_generic_array_unowned (array);
 }
 
+void test_gsequence_owned (Sequence<Value?> sequence) {
+       uint i = 0;
+
+       foreach (Value? item in sequence) {
+               i++;
+       }
+
+       assert (i == 3);
+}
+
+void test_gsequence_unowned (Sequence<Value?> sequence) {
+       uint i = 0;
+
+       foreach (unowned Value? item in sequence) {
+               i++;
+       }
+
+       assert (i == 3);
+}
+
+void test_foreach_gsequence () {
+       Value value;
+       var sequence = new Sequence<Value?> ();
+
+       value = 1;
+       sequence.append (value);
+       value = 2.0;
+       sequence.append (value);
+       value = "three";
+       sequence.append (value);
+
+       test_gsequence_owned (sequence);
+       test_gsequence_unowned (sequence);
+}
+
 void test_garray_owned (Array<Value?> array) {
        uint i = 0;
 
@@ -142,6 +177,7 @@ void main () {
        test_foreach_gvaluearray ();
        test_foreach_garray ();
        test_foreach_genericarray ();
+       test_foreach_gsequence ();
        test_foreach_const_array ();
        test_foreach_multidim_array ();
        test_foreach_slice_array ();
diff --git a/tests/control-flow/gsequence-foreach-variable.test b/tests/control-flow/gsequence-foreach-variable.test
new file mode 100644 (file)
index 0000000..305c40a
--- /dev/null
@@ -0,0 +1,7 @@
+Invalid Code
+
+void main () {
+       var sequence = new Sequence<string> ();
+       foreach (int element in sequence) {
+       }
+}
index 4daddcb845bd006c37b89269913a79416e81208f..f491c037f60dbdf04692bbecf79dd7f587e579f5 100644 (file)
@@ -183,7 +183,8 @@ public class Vala.ForeachStatement : Block {
                } 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)
-                   || collection_type.compatible (context.analyzer.garray_type))) {
+                   || collection_type.compatible (context.analyzer.garray_type)
+                   || collection_type.compatible (context.analyzer.gsequence_type))) {
                        if (collection_type.get_type_arguments ().size != 1) {
                                error = true;
                                Report.error (collection.source_reference, "missing type argument for collection");
index b49a8299d437674d56458598e9988ceedfb75fed..80e54d9c1e821def6dfb72319ee310e3d28a5ac3 100644 (file)
@@ -164,6 +164,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public DataType garray_type;
        public DataType gvaluearray_type;
        public DataType genericarray_type;
+       public DataType gsequence_type;
        public Class gerror_type;
        public DataType list_type;
        public DataType tuple_type;
@@ -230,6 +231,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        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"));
+                       gsequence_type = new ObjectType ((Class) glib_ns.scope.lookup ("Sequence"));
 
                        gerror_type = (Class) glib_ns.scope.lookup ("Error");
                        regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));