From 44195a02c9d26453dc698282deb4947425a4b0b1 Mon Sep 17 00:00:00 2001 From: Princeton Ferro Date: Mon, 24 Jan 2022 22:32:01 -0500 Subject: [PATCH] vala: Add foreach statement support for GLib.Sequence It is now possible to use foreach with a GLib.Sequence --- codegen/valaccodebasemodule.vala | 4 + codegen/valaccodecontrolflowmodule.vala | 32 ++++++ tests/Makefile.am | 1 + tests/control-flow/foreach.c-expected | 107 ++++++++++++++++++ tests/control-flow/foreach.vala | 36 ++++++ .../gsequence-foreach-variable.test | 7 ++ vala/valaforeachstatement.vala | 3 +- vala/valasemanticanalyzer.vala | 2 + 8 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 tests/control-flow/gsequence-foreach-variable.test diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index ccb2fe988..cf0d94682 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -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"); diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala index dc278e475..ce57da62f 100644 --- a/codegen/valaccodecontrolflowmodule.vala +++ b/codegen/valaccodecontrolflowmodule.vala @@ -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"); diff --git a/tests/Makefile.am b/tests/Makefile.am index b56263e8f..2103afa6e 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 \ diff --git a/tests/control-flow/foreach.c-expected b/tests/control-flow/foreach.c-expected index c7d2e6da1..23225a443 100644 --- a/tests/control-flow/foreach.c-expected +++ b/tests/control-flow/foreach.c-expected @@ -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 (); diff --git a/tests/control-flow/foreach.vala b/tests/control-flow/foreach.vala index a0a01a865..8689a18ad 100644 --- a/tests/control-flow/foreach.vala +++ b/tests/control-flow/foreach.vala @@ -68,6 +68,41 @@ void test_foreach_genericarray () { test_generic_array_unowned (array); } +void test_gsequence_owned (Sequence sequence) { + uint i = 0; + + foreach (Value? item in sequence) { + i++; + } + + assert (i == 3); +} + +void test_gsequence_unowned (Sequence 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 = 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 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 index 000000000..305c40a61 --- /dev/null +++ b/tests/control-flow/gsequence-foreach-variable.test @@ -0,0 +1,7 @@ +Invalid Code + +void main () { + var sequence = new Sequence (); + foreach (int element in sequence) { + } +} diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala index 4daddcb84..f491c037f 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -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"); diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index b49a8299d..80e54d9c1 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -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")); -- 2.47.2