summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-18 13:15:58 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-18 13:15:58 +0200
commitd551d6c268e435e2fbba22775510fbd0a54477f6 (patch)
tree2d3b652eaae430ba214db8fc7c9fd6c3c88139d6
parentf7e92aae1581203306a340b4c0059cc74adea9d6 (diff)
downloadvim-git-d551d6c268e435e2fbba22775510fbd0a54477f6.tar.gz
patch 8.2.2780: Vim9: for loop over blob doesn't workv8.2.2780
Problem: Vim9: for loop over blob doesn't work. Solution: Make it work.
-rw-r--r--src/testdir/test_blob.vim55
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c9
-rw-r--r--src/vim9execute.c39
4 files changed, 72 insertions, 33 deletions
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index 21f90efb1..fa482b432 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -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()
diff --git a/src/version.c b/src/version.c
index 12a51c912..c3e2ea852 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2780,
+/**/
2779,
/**/
2778,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 9cb71295c..961050f98 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
}
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 8a985214c..4e1af4e58 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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;