]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
codegen: Add foreach support for strings
authorFrederik Zipp <fzipp@gmx.de>
Sun, 1 Aug 2010 10:54:37 +0000 (12:54 +0200)
committerRico Tzschichholz <ricotz@ubuntu.com>
Wed, 11 Jan 2023 18:54:08 +0000 (19:54 +0100)
Fixes https://gitlab.gnome.org/GNOME/vala/issues/108

codegen/valaccodecontrolflowmodule.vala
tests/control-flow/foreach.c-expected
tests/control-flow/foreach.vala
vala/valaforeachstatement.vala

index 9ecbced2f85826495994883a12a40b0786132a60..9a68579b3fd703d8b6991215d628a3326cab54a9 100644 (file)
@@ -441,6 +441,40 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
 
                        stmt.body.emit (this);
 
+                       ccode.close ();
+               } else if (stmt.collection.value_type.compatible (string_type)) {
+                       // iterating over a string
+
+                       var validate = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_validate"));
+                       validate.add_argument (get_variable_cexpression (get_local_cname (collection_backup)));
+                       validate.add_argument (new CCodeConstant ("-1"));
+                       validate.add_argument (new CCodeConstant ("NULL"));
+                       var cassert = new CCodeFunctionCall (new CCodeIdentifier ("_vala_warn_if_fail"));
+                       cassert.add_argument (validate);
+                       cassert.add_argument (new CCodeConstant ("\"Invalid UTF-8 string\""));
+                       requires_assert = true;
+                       ccode.add_expression (cassert);
+
+                       var iterator_variable = new LocalVariable (collection_type, "%s_iter".printf (stmt.variable_name));
+                       visit_local_variable (iterator_variable);
+                       var string_iter = get_variable_cname (get_local_cname (iterator_variable));
+
+                       var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (string_iter)), new CCodeConstant ("'\\0'"));
+                       var next_char_call = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_next_char"));
+                       next_char_call.add_argument (get_variable_cexpression (string_iter));
+
+                       ccode.open_for (new CCodeAssignment (get_variable_cexpression (string_iter), get_variable_cexpression (collection_backup.name)),
+                                       ccond,
+                                       new CCodeAssignment (get_variable_cexpression (string_iter), next_char_call));
+
+                       var element_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_utf8_get_char"));
+                       element_expr.add_argument (get_variable_cexpression (string_iter));
+
+                       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 c402e1c12deefbef834cd44e3634be3d8d3bf132..3263a32efb97cd7c3e8ce8b425632ae7ad5e8c26 100644 (file)
@@ -46,6 +46,7 @@ static void _vala_GValue_free_function_content_of (gpointer data);
 VALA_EXTERN void test_foreach_multidim_array (void);
 VALA_EXTERN void test_foreach_const_array (void);
 VALA_EXTERN void test_foreach_slice_array (void);
+VALA_EXTERN void test_foreach_string (void);
 static void _vala_main (void);
 
 const gint FOO[6] = {1, 2, 3, 4, 5, 6};
@@ -669,6 +670,36 @@ test_foreach_slice_array (void)
        foo = (g_free (foo), NULL);
 }
 
+void
+test_foreach_string (void)
+{
+       guint i = 0U;
+       gchar* s = NULL;
+       gchar* _tmp0_;
+       const gchar* _tmp1_;
+       i = (guint) 0;
+       _tmp0_ = g_strdup ("abc àçêö 你好");
+       s = _tmp0_;
+       _tmp1_ = s;
+       {
+               const gchar* c_collection = NULL;
+               const gchar* c_iter = NULL;
+               c_collection = _tmp1_;
+               _vala_warn_if_fail (g_utf8_validate (c_collection, -1, NULL), "Invalid UTF-8 string");
+               for (c_iter = c_collection; (*c_iter) != '\0'; c_iter = g_utf8_next_char (c_iter)) {
+                       gunichar c = 0U;
+                       c = g_utf8_get_char (c_iter);
+                       {
+                               guint _tmp2_;
+                               _tmp2_ = i;
+                               i = _tmp2_ + 1;
+                       }
+               }
+       }
+       _vala_assert (i == ((guint) 11), "i == 11");
+       _g_free0 (s);
+}
+
 static void
 _vala_main (void)
 {
@@ -679,6 +710,7 @@ _vala_main (void)
        test_foreach_const_array ();
        test_foreach_multidim_array ();
        test_foreach_slice_array ();
+       test_foreach_string ();
 }
 
 int
index 8689a18ad9c70d03b589f0e5198b513690fcbfe8..83cef663a9c4324e0a85acce5fbf0c503627e738 100644 (file)
@@ -173,6 +173,17 @@ void test_foreach_slice_array () {
        assert (result == "2345");
 }
 
+void test_foreach_string () {
+       uint i = 0;
+       string s = "abc àçêö 你好"; // Ni hao
+
+       foreach (unichar c in s) {
+               i++;
+       }
+
+       assert (i == 11);
+}
+
 void main () {
        test_foreach_gvaluearray ();
        test_foreach_garray ();
@@ -181,4 +192,5 @@ void main () {
        test_foreach_const_array ();
        test_foreach_multidim_array ();
        test_foreach_slice_array ();
+       test_foreach_string ();
 }
index 84370e5b0e53f89d4ef84a9d3af0b4a22d3579dd..69d49eccb445b1f663efd65c588e75992343fb4d 100644 (file)
@@ -194,6 +194,8 @@ public class Vala.ForeachStatement : Block {
                        return check_without_iterator (context, collection_type, collection_type.get_type_arguments ().get (0));
                } else if (context.profile == Profile.GOBJECT && collection_type.compatible (context.analyzer.gvaluearray_type)) {
                        return check_without_iterator (context, collection_type, context.analyzer.gvalue_type);
+               } else if (context.profile == Profile.GOBJECT && collection_type.compatible (context.analyzer.string_type)) {
+                       return check_without_iterator (context, collection_type, context.analyzer.unichar_type);
                } else {
                        return check_with_iterator (context, collection_type);
                }