To: vim_dev@googlegroups.com Subject: Patch 8.2.2780 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2780 Problem: Vim9: for loop over blob doesn't work. Solution: Make it work. Files: src/vim9compile.c, src/vim9execute.c, src/testdir/test_blob.vim *** ../vim-8.2.2779/src/vim9compile.c 2021-04-17 20:44:52.438520729 +0200 --- src/vim9compile.c 2021-04-18 13:10:48.610166634 +0200 *************** *** 7508,7520 **** } arg_end = arg; ! // If we know the type of "var" and it is a not a list or string 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) { - // TODO: support Blob semsg(_(e_for_loop_on_str_not_supported), vartype_name(vartype->tt_type)); drop_scope(cctx); --- 7508,7519 ---- } arg_end = arg; ! // 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_BLOB && vartype->tt_type != VAR_ANY) { semsg(_(e_for_loop_on_str_not_supported), vartype_name(vartype->tt_type)); drop_scope(cctx); *************** *** 7523,7528 **** --- 7522,7529 ---- 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,7536 **** 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 item_type = vartype->tt_member->tt_member; } --- 7531,7537 ---- 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 for each lhs item_type = vartype->tt_member->tt_member; } *** ../vim-8.2.2779/src/vim9execute.c 2021-04-17 20:44:52.442520718 +0200 --- src/vim9execute.c 2021-04-18 13:14:50.845114758 +0200 *************** *** 2900,2907 **** { 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. ++idxtv->vval.v_number; if (str == NULL || str[idxtv->vval.v_number] == NUL) { --- 2900,2907 ---- { char_u *str = ltv->vval.v_string; ! // 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,2918 **** --- 2913,2919 ---- { 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,2929 **** idxtv->vval.v_number += clen - 1; } } else { - // TODO: support Blob semsg(_(e_for_loop_on_str_not_supported), vartype_name(ltv->v_type)); goto failed; --- 2922,2962 ---- 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 { semsg(_(e_for_loop_on_str_not_supported), vartype_name(ltv->v_type)); goto failed; *** ../vim-8.2.2779/src/testdir/test_blob.vim 2021-04-17 20:44:52.442520718 +0200 --- src/testdir/test_blob.vim 2021-04-18 13:01:39.892653660 +0200 *************** *** 283,315 **** 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 call remove(blob, 0) ! elseif i == 3 ! call remove(blob, 3) ! endif ! let i += 1 ! endfor ! call assert_equal(5, i) endfunc func Test_blob_concatenate() --- 283,318 ---- endfunc func Test_blob_for_loop() ! 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) ! 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() *** ../vim-8.2.2779/src/version.c 2021-04-17 21:22:46.351232494 +0200 --- src/version.c 2021-04-18 12:53:17.195236010 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2780, /**/ -- hundred-and-one symptoms of being an internet addict: 117. You are more comfortable typing in html. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///