]> granicus.if.org Git - vim/commitdiff
patch 8.2.2780: Vim9: for loop over blob doesn't work v8.2.2780
authorBram Moolenaar <Bram@vim.org>
Sun, 18 Apr 2021 11:15:58 +0000 (13:15 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 18 Apr 2021 11:15:58 +0000 (13:15 +0200)
Problem:    Vim9: for loop over blob doesn't work.
Solution:   Make it work.

src/testdir/test_blob.vim
src/version.c
src/vim9compile.c
src/vim9execute.c

index 21f90efb18cd33a338288d8a37f2d82107c1596c..fa482b432fb95aeaefa61dbb3b64df28ee56bd31 100644 (file)
@@ -283,33 +283,36 @@ func Test_blob_index_assign()
 endfunc
 
 func Test_blob_for_loop()
-  let blob = 0z00010203
-  let i = 0
-  for byte in blob
-    call assert_equal(i, byte)
-    let i += 1
-  endfor
-    call assert_equal(4, i)
-
-  let blob = 0z00
-  call remove(blob, 0)
-  call assert_equal(0, len(blob))
-  for byte in blob
-    call assert_error('loop over empty blob')
-  endfor
-
-  let blob = 0z0001020304
-  let i = 0
-  for byte in blob
-    call assert_equal(i, byte)
-    if i == 1
+  let lines =<< trim END
+      VAR blob = 0z00010203
+      VAR i = 0
+      for byte in blob
+        call assert_equal(i, byte)
+        LET i += 1
+      endfor
+      call assert_equal(4, i)
+
+      LET blob = 0z00
       call remove(blob, 0)
-    elseif i == 3
-      call remove(blob, 3)
-    endif
-    let i += 1
-  endfor
-  call assert_equal(5, i)
+      call assert_equal(0, len(blob))
+      for byte in blob
+        call assert_report('loop over empty blob')
+      endfor
+
+      LET blob = 0z0001020304
+      LET i = 0
+      for byte in blob
+        call assert_equal(i, byte)
+        if i == 1
+          call remove(blob, 0)
+        elseif i == 3
+          call remove(blob, 3)
+        endif
+        LET i += 1
+      endfor
+      call assert_equal(5, i)
+  END
+  call CheckLegacyAndVim9Success(lines)
 endfunc
 
 func Test_blob_concatenate()
index 12a51c9128d259a6322de817abcedd7bd100f3e3..c3e2ea852752dfeceeeb88a44e174b9049f75c89 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2780,
 /**/
     2779,
 /**/
index 9cb71295cd63c85dcee540ce81077565ec9fb8f6..961050f985d4ad3c82dda04649f37cfb01ce57c5 100644 (file)
@@ -7508,13 +7508,12 @@ compile_for(char_u *arg_start, cctx_T *cctx)
     }
     arg_end = arg;
 
-    // If we know the type of "var" and it is a not a list or string we can
+    // If we know the type of "var" and it is a not a supported type we can
     // give an error now.
     vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
     if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING
-                                               && vartype->tt_type != VAR_ANY)
+               && vartype->tt_type != VAR_BLOB && vartype->tt_type != VAR_ANY)
     {
-       // TODO: support Blob
        semsg(_(e_for_loop_on_str_not_supported),
                                               vartype_name(vartype->tt_type));
        drop_scope(cctx);
@@ -7523,6 +7522,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
 
     if (vartype->tt_type == VAR_STRING)
        item_type = &t_string;
+    else if (vartype->tt_type == VAR_BLOB)
+       item_type = &t_number;
     else if (vartype->tt_type == VAR_LIST
                                     && vartype->tt_member->tt_type != VAR_ANY)
     {
@@ -7530,7 +7531,7 @@ compile_for(char_u *arg_start, cctx_T *cctx)
            item_type = vartype->tt_member;
        else if (vartype->tt_member->tt_type == VAR_LIST
                      && vartype->tt_member->tt_member->tt_type != VAR_ANY)
-           // TODO: should get the type from 
+           // TODO: should get the type for each lhs
            item_type = vartype->tt_member->tt_member;
     }
 
index 8a985214c1ed7ca93604b67393c419845ba16dd7..4e1af4e583d2f97ce05025e05526764efe680cd4 100644 (file)
@@ -2900,8 +2900,8 @@ call_def_function(
                    {
                        char_u  *str = ltv->vval.v_string;
 
-                       // Push the next character from the string.  The index
-                       // is for the last byte of the previous character.
+                       // The index is for the last byte of the previous
+                       // character.
                        ++idxtv->vval.v_number;
                        if (str == NULL || str[idxtv->vval.v_number] == NUL)
                        {
@@ -2913,6 +2913,7 @@ call_def_function(
                        {
                            int clen = mb_ptr2len(str + idxtv->vval.v_number);
 
+                           // Push the next character from the string.
                            tv = STACK_TV_BOT(0);
                            tv->v_type = VAR_STRING;
                            tv->vval.v_string = vim_strnsave(
@@ -2921,9 +2922,41 @@ call_def_function(
                            idxtv->vval.v_number += clen - 1;
                        }
                    }
+                   else if (ltv->v_type == VAR_BLOB)
+                   {
+                       blob_T  *blob = ltv->vval.v_blob;
+
+                       // When we get here the first time make a copy of the
+                       // blob, so that the iteration still works when it is
+                       // changed.
+                       if (idxtv->vval.v_number == -1 && blob != NULL)
+                       {
+                           blob_copy(blob, ltv);
+                           blob_unref(blob);
+                           blob = ltv->vval.v_blob;
+                       }
+
+                       // The index is for the previous byte.
+                       ++idxtv->vval.v_number;
+                       if (blob == NULL
+                                    || idxtv->vval.v_number >= blob_len(blob))
+                       {
+                           // past the end of the blob, jump to "endfor"
+                           ectx.ec_iidx = iptr->isn_arg.forloop.for_end;
+                           may_restore_cmdmod(&funclocal);
+                       }
+                       else
+                       {
+                           // Push the next byte from the blob.
+                           tv = STACK_TV_BOT(0);
+                           tv->v_type = VAR_NUMBER;
+                           tv->vval.v_number = blob_get(blob,
+                                                        idxtv->vval.v_number);
+                           ++ectx.ec_stack.ga_len;
+                       }
+                   }
                    else
                    {
-                       // TODO: support Blob
                        semsg(_(e_for_loop_on_str_not_supported),
                                                    vartype_name(ltv->v_type));
                        goto failed;