1
0
forked from aniani/vim

patch 8.2.2780: Vim9: for loop over blob doesn't work

Problem:    Vim9: for loop over blob doesn't work.
Solution:   Make it work.
This commit is contained in:
Bram Moolenaar
2021-04-18 13:15:58 +02:00
parent f7e92aae15
commit d551d6c268
4 changed files with 71 additions and 32 deletions

View File

@@ -283,23 +283,24 @@ func Test_blob_index_assign()
endfunc endfunc
func Test_blob_for_loop() func Test_blob_for_loop()
let blob = 0z00010203 let lines =<< trim END
let i = 0 VAR blob = 0z00010203
VAR i = 0
for byte in blob for byte in blob
call assert_equal(i, byte) call assert_equal(i, byte)
let i += 1 LET i += 1
endfor endfor
call assert_equal(4, i) call assert_equal(4, i)
let blob = 0z00 LET blob = 0z00
call remove(blob, 0) call remove(blob, 0)
call assert_equal(0, len(blob)) call assert_equal(0, len(blob))
for byte in blob for byte in blob
call assert_error('loop over empty blob') call assert_report('loop over empty blob')
endfor endfor
let blob = 0z0001020304 LET blob = 0z0001020304
let i = 0 LET i = 0
for byte in blob for byte in blob
call assert_equal(i, byte) call assert_equal(i, byte)
if i == 1 if i == 1
@@ -307,9 +308,11 @@ func Test_blob_for_loop()
elseif i == 3 elseif i == 3
call remove(blob, 3) call remove(blob, 3)
endif endif
let i += 1 LET i += 1
endfor endfor
call assert_equal(5, i) call assert_equal(5, i)
END
call CheckLegacyAndVim9Success(lines)
endfunc endfunc
func Test_blob_concatenate() func Test_blob_concatenate()

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2780,
/**/ /**/
2779, 2779,
/**/ /**/

View File

@@ -7508,13 +7508,12 @@ compile_for(char_u *arg_start, cctx_T *cctx)
} }
arg_end = arg; 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. // give an error now.
vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1]; vartype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
if (vartype->tt_type != VAR_LIST && vartype->tt_type != VAR_STRING 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), semsg(_(e_for_loop_on_str_not_supported),
vartype_name(vartype->tt_type)); vartype_name(vartype->tt_type));
drop_scope(cctx); drop_scope(cctx);
@@ -7523,6 +7522,8 @@ compile_for(char_u *arg_start, cctx_T *cctx)
if (vartype->tt_type == VAR_STRING) if (vartype->tt_type == VAR_STRING)
item_type = &t_string; item_type = &t_string;
else if (vartype->tt_type == VAR_BLOB)
item_type = &t_number;
else if (vartype->tt_type == VAR_LIST else if (vartype->tt_type == VAR_LIST
&& vartype->tt_member->tt_type != VAR_ANY) && 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; item_type = vartype->tt_member;
else if (vartype->tt_member->tt_type == VAR_LIST else if (vartype->tt_member->tt_type == VAR_LIST
&& vartype->tt_member->tt_member->tt_type != VAR_ANY) && 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; item_type = vartype->tt_member->tt_member;
} }

View File

@@ -2900,8 +2900,8 @@ call_def_function(
{ {
char_u *str = ltv->vval.v_string; char_u *str = ltv->vval.v_string;
// Push the next character from the string. The index // The index is for the last byte of the previous
// is for the last byte of the previous character. // character.
++idxtv->vval.v_number; ++idxtv->vval.v_number;
if (str == NULL || str[idxtv->vval.v_number] == NUL) 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); int clen = mb_ptr2len(str + idxtv->vval.v_number);
// Push the next character from the string.
tv = STACK_TV_BOT(0); tv = STACK_TV_BOT(0);
tv->v_type = VAR_STRING; tv->v_type = VAR_STRING;
tv->vval.v_string = vim_strnsave( tv->vval.v_string = vim_strnsave(
@@ -2921,9 +2922,41 @@ call_def_function(
idxtv->vval.v_number += clen - 1; 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 else
{ {
// TODO: support Blob
semsg(_(e_for_loop_on_str_not_supported), semsg(_(e_for_loop_on_str_not_supported),
vartype_name(ltv->v_type)); vartype_name(ltv->v_type));
goto failed; goto failed;