]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Vala: Improve the support of the method .printf().
authorBruno Haible <bruno@clisp.org>
Sat, 27 Jul 2024 17:12:51 +0000 (19:12 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 27 Jul 2024 17:12:51 +0000 (19:12 +0200)
* gettext-tools/src/x-vala.c (enum token_type_ty): New enum item
token_type_compound_assign.
(phase3_get): Recognize the compound assignment operators as
token_type_compound_assign instead of token_type_assign.
(extract_balanced): Invoke new_sub_region instead of inheriting_region. Invoke
set_format_flag_on_region instead of iterating through the region. When
encountering an operator, close the inner_region and open a new inner_region.
After 'return', use the passthrough_context_list_iterator, not the
null_context_list_iterator.
* gettext-tools/tests/xgettext-vala-6: Add many more test cases.

gettext-tools/src/x-vala.c
gettext-tools/tests/xgettext-vala-6

index cbcf6146b4a7d438d0d1f322ebff869061ffac83..74cfbeea426a1d9a7fe2b02abc446ebec1c14296 100644 (file)
 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
 
 /* The Vala syntax is defined in the Vala Reference Manual
-   https://www.vala-project.org/doc/vala/.
-   See also vala/valascanner.vala.  */
+   https://gnome.pages.gitlab.gnome.org/vala/manual/index.html.
+   See also vala/valascanner.vala.
+
+   It supports string formatting through functions and methods, namely
+   through the string.printf and string.vprintf methods:
+   <https://valadoc.org/glib-2.0/string.printf.html>
+   <https://valadoc.org/glib-2.0/string.vprintf.html>
+ */
 
 /* ====================== Keyword set customization.  ====================== */
 
@@ -390,7 +396,8 @@ enum token_type_ty
   token_type_rparen,                    /* ) */
   token_type_lbrace,                    /* { */
   token_type_rbrace,                    /* } */
-  token_type_assign,                    /* = += -= *= /= %= <<= >>= &= |= ^= */
+  token_type_assign,                    /* = */
+  token_type_compound_assign,           /* += -= *= /= %= <<= >>= &= |= ^= */
   token_type_return,                    /* return */
   token_type_plus,                      /* + */
   token_type_arithmetic_operator,       /* - * / % << >> & | ^ ~ */
@@ -1018,6 +1025,7 @@ phase3_get (token_ty *tp)
             case token_type_lparen:
             case token_type_lbrace:
             case token_type_assign:
+            case token_type_compound_assign:
             case token_type_return:
             case token_type_plus:
             case token_type_arithmetic_operator:
@@ -1033,7 +1041,7 @@ phase3_get (token_ty *tp)
               {
                 int c2 = phase2_getc ();
                 if (c2 == '=')
-                  tp->type = last_token_type = token_type_assign;
+                  tp->type = last_token_type = token_type_compound_assign;
                 else
                   {
                     phase2_ungetc (c2);
@@ -1069,7 +1077,7 @@ phase3_get (token_ty *tp)
                 tp->type = last_token_type = token_type_other;
                 break;
               case '=':
-                tp->type = last_token_type = token_type_assign;
+                tp->type = last_token_type = token_type_compound_assign;
                 break;
               default:
                 phase2_ungetc (c2);
@@ -1088,7 +1096,7 @@ phase3_get (token_ty *tp)
                 tp->type = last_token_type = token_type_other;
                 break;
               case '=':
-                tp->type = last_token_type = token_type_assign;
+                tp->type = last_token_type = token_type_compound_assign;
                 break;
               default:
                 phase2_ungetc (c2);
@@ -1102,7 +1110,7 @@ phase3_get (token_ty *tp)
           {
             int c2 = phase2_getc ();
             if (c2 == '=')
-              tp->type = last_token_type = token_type_assign;
+              tp->type = last_token_type = token_type_compound_assign;
             else
               {
                 phase2_ungetc (c2);
@@ -1116,7 +1124,7 @@ phase3_get (token_ty *tp)
           {
             int c2 = phase2_getc ();
             if (c2 == '=')
-             tp->type = last_token_type = token_type_assign;
+             tp->type = last_token_type = token_type_compound_assign;
             else
               {
                 phase2_ungetc (c2);
@@ -1171,7 +1179,7 @@ phase3_get (token_ty *tp)
               {
                 int c3 = phase2_getc ();
                 if (c3 == '=')
-                  tp->type = last_token_type = token_type_assign;
+                  tp->type = last_token_type = token_type_compound_assign;
                 else
                   {
                     phase2_ungetc (c2);
@@ -1202,7 +1210,7 @@ phase3_get (token_ty *tp)
             if (c2 == c)
              tp->type = last_token_type = token_type_logic_operator;
             else if (c2 == '=')
-             tp->type = last_token_type = token_type_assign;
+             tp->type = last_token_type = token_type_compound_assign;
             else
               {
                 phase2_ungetc (c2);
@@ -1370,10 +1378,11 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
   /* Context iterator that will be used if the next token is a '('.  */
   flag_context_list_iterator_ty next_context_iter =
     passthrough_context_list_iterator;
+  /* Current context.  */
+  flag_context_ty curr_context =
+    flag_context_list_iterator_advance (&context_iter);
   /* Current region.  */
-  flag_region_ty *inner_region =
-    inheriting_region (outer_region,
-                       flag_context_list_iterator_advance (&context_iter));
+  flag_region_ty *inner_region = new_sub_region (outer_region, curr_context);
 
   /* Start state is 0.  */
   state = 0;
@@ -1438,16 +1447,8 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
                   {
                     /* Mark the messages found in the region as c-format
                        a posteriori.  */
-                    inner_region->for_formatstring[XFORMAT_PRIMARY].is_format = yes_according_to_context;
-                    struct remembered_message_list_ty *rmlp =
-                      inner_region->for_formatstring[XFORMAT_PRIMARY].remembered;
-                    size_t i;
-                    for (i = 0; i < rmlp->nitems; i++)
-                      {
-                        struct remembered_message_ty *rmp = &rmlp->item[i];
-                        set_format_flag_from_context (rmp->mp, rmp->plural, &rmp->pos,
-                                                      XFORMAT_PRIMARY, inner_region);
-                      }
+                    set_format_flag_on_region (inner_region,
+                                               XFORMAT_PRIMARY, yes_according_to_context);
                   }
                 x_vala_unlex (&token3);
               }
@@ -1472,10 +1473,59 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
         case token_type_comma:
           arg++;
           unref_region (inner_region);
-          inner_region =
-            inheriting_region (outer_region,
-                               flag_context_list_iterator_advance (
-                                 &context_iter));
+          curr_context = flag_context_list_iterator_advance (&context_iter);
+          inner_region = new_sub_region (outer_region, curr_context);
+          next_context_iter = passthrough_context_list_iterator;
+          state = 0;
+          continue;
+
+        case token_type_question:
+          /* In an expression A ? B : C, each of A, B, C is a distinct
+             sub-region, and since the value of A is not the value of entire
+             expression, if later set_format_flag_on_region is called on this
+             region or an ancestor region, it shall not have an effect on the
+             remembered messages of A.  */
+          inner_region->inherit_from_parent_region = false;
+          unref_region (inner_region);
+          inner_region = new_sub_region (outer_region, curr_context);
+          next_context_iter = passthrough_context_list_iterator;
+          state = 0;
+          continue;
+
+        case token_type_colon:
+          /* In an expression A ? B : C, each of A, B, C is a distinct
+             sub-region.  */
+          unref_region (inner_region);
+          inner_region = new_sub_region (outer_region, curr_context);
+          next_context_iter = passthrough_context_list_iterator;
+          state = 0;
+          continue;
+
+        case token_type_assign:
+          /* In an expression A = B, A and B are distinct sub-regions.
+             The value of B is the value of the entire expression.  */
+          inner_region->inherit_from_parent_region = false;
+          unref_region (inner_region);
+          inner_region = new_sub_region (outer_region, curr_context);
+          next_context_iter = passthrough_context_list_iterator;
+          state = 0;
+          continue;
+
+        case token_type_plus:
+        case token_type_arithmetic_operator:
+        case token_type_equality_test_operator:
+        case token_type_logic_operator:
+        case token_type_compound_assign:
+          /* When an expression contains one of these operators, neither the
+             value on the left of the operator nor the value on the right of the
+             operator is string-valued and the value of the entire expression.
+             Therefore, if later set_format_flag_on_region is called on this
+             region or an ancestor region, it shall not have an effect on the
+             remembered messages of this region.  */
+          inner_region->inherit_from_parent_region = false;
+          unref_region (inner_region);
+          inner_region = new_sub_region (outer_region, curr_context);
+          inner_region->inherit_from_parent_region = false;
           next_context_iter = passthrough_context_list_iterator;
           state = 0;
           continue;
@@ -1531,17 +1581,14 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
           state = 0;
           continue;
 
+        case token_type_return:
+          next_context_iter = passthrough_context_list_iterator;
+          state = 0;
+          continue;
+
         case token_type_character_constant:
         case token_type_lbrace:
         case token_type_rbrace:
-        case token_type_assign:
-        case token_type_return:
-        case token_type_plus:
-        case token_type_arithmetic_operator:
-        case token_type_equality_test_operator:
-        case token_type_logic_operator:
-        case token_type_question:
-        case token_type_colon:
         case token_type_number:
         case token_type_string_template:
         case token_type_regex_literal:
index f215f8218ec885472110e3967dcef7a287605bef..986545d134a0f17cc941ac6b2adfe3c7583bd6e2 100755 (executable)
@@ -8,10 +8,56 @@
 cat <<\EOF > xg-vala-6.vala
 "<b>%s</b>".printf(_("Hello 1"));
 _("Explanation: %s").printf(_("Hello 2"));
-_("No error 1");
-_("No error 2").printf();
-(_("No error 3")).printf();
-foo(_("No error 4")).printf();
+_("test case 1");
+_("test case 2").printf();
+(_("test case 3"));
+(_("test case 4")).printf();
+((_("test case 5")));
+((_("test case 6"))).printf();
+return _("test case 10");
+return _("test case 11").printf();
+return (_("test case 12").printf());
+return (_("test case 13")).printf();
+foo (_("test case 15"));
+foo (_("test case 16")).printf();
+(foo (_("test case 17"))).printf();
+(foo (_("test case 18")).printf());
+foo (_("test case 19").printf());
+foo + _("test case 20");
+foo + _("test case 21").printf();
+(foo + _("test case 22")).printf();
+_("test case 23") + foo;
+_("test case 24").printf() + foo;
+(_("test case 25") + foo).printf();
+_("test case 26 a") + _("test case 26 b");
+_("test case 27 a").printf() + _("test case 27 b");
+_("test case 28 a") + _("test case 28 b").printf();
+_("test case 29 a").printf() + _("test case 29 b").printf();
+(_("test case 30 a") + _("test case 30 b")).printf();
+return _("test case 31 a") + _("test case 31 b");
+return _("test case 32 a").printf() + _("test case 32 b");
+return _("test case 33 a") + _("test case 33 b").printf();
+return _("test case 34 a").printf() + _("test case 34 b").printf();
+return (_("test case 35 a") + _("test case 35 b")).printf();
+return _("test case 36 a") + (_("test case 36 b")).printf() + _("test case 36 c").printf();
+return _("test case 37 a") + _("test case 37 b").printf() + (_("test case 37 c")).printf();
+return _("test case 38 a") + (_("test case 38 b")).printf() + (_("test case 38 c")).printf();
+foo ? _("test case 40 a") : _("test case 40 b");
+foo ? _("test case 41 a").printf() : _("test case 41 b");
+foo ? _("test case 42 a") : _("test case 42 b").printf();
+foo ? _("test case 43 a").printf() : _("test case 43 b").printf();
+(foo ? _("test case 44 a") : _("test case 44 b"));
+(foo ? _("test case 45 a") : _("test case 45 b")).printf();
+s = (_("test case 46")).printf();
+(s = _("test case 47")).printf();
+s += (_("test case 48")).printf();
+(s += _("test case 49")).printf();
+return _("test case 50 a")
+       + _("test case 50 b").printf()
+       + (_("test case 50 c")).printf()
+       + foo(_("test case 50 d")).printf()
+       + (b ? _("test case 50 e") : _("test case 50 f")).printf()
+       + (b ? foo + _("test case 50 g") : _("test case 50 h") + bar).printf();
 Posix.printf(_("Hello 3"));
 Posix.printf(_("Hello 4 %s!"), _("Sir"));
 EOF
@@ -30,18 +76,262 @@ msgstr ""
 msgid "Hello 2"
 msgstr ""
 
-msgid "No error 1"
+msgid "test case 1"
 msgstr ""
 
 #, c-format
-msgid "No error 2"
+msgid "test case 2"
+msgstr ""
+
+msgid "test case 3"
+msgstr ""
+
+#, c-format
+msgid "test case 4"
+msgstr ""
+
+msgid "test case 5"
+msgstr ""
+
+#, c-format
+msgid "test case 6"
+msgstr ""
+
+msgid "test case 10"
+msgstr ""
+
+#, c-format
+msgid "test case 11"
+msgstr ""
+
+#, c-format
+msgid "test case 12"
+msgstr ""
+
+#, c-format
+msgid "test case 13"
+msgstr ""
+
+msgid "test case 15"
+msgstr ""
+
+msgid "test case 16"
+msgstr ""
+
+msgid "test case 17"
+msgstr ""
+
+msgid "test case 18"
+msgstr ""
+
+#, c-format
+msgid "test case 19"
+msgstr ""
+
+msgid "test case 20"
+msgstr ""
+
+#, c-format
+msgid "test case 21"
+msgstr ""
+
+msgid "test case 22"
+msgstr ""
+
+msgid "test case 23"
+msgstr ""
+
+#, c-format
+msgid "test case 24"
+msgstr ""
+
+msgid "test case 25"
+msgstr ""
+
+msgid "test case 26 a"
+msgstr ""
+
+msgid "test case 26 b"
+msgstr ""
+
+#, c-format
+msgid "test case 27 a"
+msgstr ""
+
+msgid "test case 27 b"
+msgstr ""
+
+msgid "test case 28 a"
+msgstr ""
+
+#, c-format
+msgid "test case 28 b"
+msgstr ""
+
+#, c-format
+msgid "test case 29 a"
+msgstr ""
+
+#, c-format
+msgid "test case 29 b"
+msgstr ""
+
+msgid "test case 30 a"
+msgstr ""
+
+msgid "test case 30 b"
+msgstr ""
+
+msgid "test case 31 a"
+msgstr ""
+
+msgid "test case 31 b"
+msgstr ""
+
+#, c-format
+msgid "test case 32 a"
+msgstr ""
+
+msgid "test case 32 b"
+msgstr ""
+
+msgid "test case 33 a"
+msgstr ""
+
+#, c-format
+msgid "test case 33 b"
+msgstr ""
+
+#, c-format
+msgid "test case 34 a"
 msgstr ""
 
 #, c-format
-msgid "No error 3"
+msgid "test case 34 b"
+msgstr ""
+
+msgid "test case 35 a"
+msgstr ""
+
+msgid "test case 35 b"
+msgstr ""
+
+msgid "test case 36 a"
+msgstr ""
+
+#, c-format
+msgid "test case 36 b"
+msgstr ""
+
+#, c-format
+msgid "test case 36 c"
+msgstr ""
+
+msgid "test case 37 a"
+msgstr ""
+
+#, c-format
+msgid "test case 37 b"
+msgstr ""
+
+#, c-format
+msgid "test case 37 c"
+msgstr ""
+
+msgid "test case 38 a"
+msgstr ""
+
+#, c-format
+msgid "test case 38 b"
+msgstr ""
+
+#, c-format
+msgid "test case 38 c"
+msgstr ""
+
+msgid "test case 40 a"
+msgstr ""
+
+msgid "test case 40 b"
+msgstr ""
+
+#, c-format
+msgid "test case 41 a"
+msgstr ""
+
+msgid "test case 41 b"
+msgstr ""
+
+msgid "test case 42 a"
+msgstr ""
+
+#, c-format
+msgid "test case 42 b"
+msgstr ""
+
+#, c-format
+msgid "test case 43 a"
+msgstr ""
+
+#, c-format
+msgid "test case 43 b"
+msgstr ""
+
+msgid "test case 44 a"
+msgstr ""
+
+msgid "test case 44 b"
+msgstr ""
+
+#, c-format
+msgid "test case 45 a"
+msgstr ""
+
+#, c-format
+msgid "test case 45 b"
+msgstr ""
+
+#, c-format
+msgid "test case 46"
+msgstr ""
+
+#, c-format
+msgid "test case 47"
+msgstr ""
+
+#, c-format
+msgid "test case 48"
+msgstr ""
+
+msgid "test case 49"
+msgstr ""
+
+msgid "test case 50 a"
+msgstr ""
+
+#, c-format
+msgid "test case 50 b"
+msgstr ""
+
+#, c-format
+msgid "test case 50 c"
+msgstr ""
+
+msgid "test case 50 d"
+msgstr ""
+
+#, c-format
+msgid "test case 50 e"
+msgstr ""
+
+#, c-format
+msgid "test case 50 f"
+msgstr ""
+
+msgid "test case 50 g"
 msgstr ""
 
-msgid "No error 4"
+msgid "test case 50 h"
 msgstr ""
 
 msgid "Hello 3"
@@ -56,7 +346,7 @@ msgstr ""
 EOF
 
 : ${DIFF=diff}
-${DIFF} xg-vala-6.ok xg-vala-6.po
+${DIFF} -u xg-vala-6.ok xg-vala-6.po
 result=$?
 
 exit $result