# HG changeset patch # User Bram Moolenaar # Date 1618165804 -7200 # Node ID aa150abca273ad76e94aa0cc2cd040c159c0f92a # Parent 8f23b64d87fa65ba5c82a566b1b3be81f4e375d2 patch 8.2.2756: Vim9: blob index and slice not implemented yet Commit: https://github.com/vim/vim/commit/cfc3023cb6ce5aaec13f49bc4b821feb05e3fb03 Author: Bram Moolenaar Date: Sun Apr 11 20:26:34 2021 +0200 patch 8.2.2756: Vim9: blob index and slice not implemented yet Problem: Vim9: blob index and slice not implemented yet. Solution: Implement blob index and slice. diff --git a/src/blob.c b/src/blob.c --- a/src/blob.c +++ b/src/blob.c @@ -259,6 +259,83 @@ failed: return NULL; } + int +blob_slice_or_index( + blob_T *blob, + int is_range, + varnumber_T n1, + varnumber_T n2, + int exclusive, + typval_T *rettv) +{ + long len = blob_len(blob); + + if (is_range) + { + // The resulting variable is a sub-blob. If the indexes + // are out of range the result is empty. + if (n1 < 0) + { + n1 = len + n1; + if (n1 < 0) + n1 = 0; + } + if (n2 < 0) + n2 = len + n2; + else if (n2 >= len) + n2 = len - (exclusive ? 0 : 1); + if (exclusive) + --n2; + if (n1 >= len || n2 < 0 || n1 > n2) + { + clear_tv(rettv); + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = NULL; + } + else + { + blob_T *new_blob = blob_alloc(); + long i; + + if (new_blob != NULL) + { + if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL) + { + blob_free(new_blob); + return FAIL; + } + new_blob->bv_ga.ga_len = n2 - n1 + 1; + for (i = n1; i <= n2; i++) + blob_set(new_blob, i - n1, blob_get(blob, i)); + + clear_tv(rettv); + rettv_blob_set(rettv, new_blob); + } + } + } + else + { + // The resulting variable is a byte value. + // If the index is too big or negative that is an error. + if (n1 < 0) + n1 = len + n1; + if (n1 < len && n1 >= 0) + { + int v = blob_get(blob, n1); + + clear_tv(rettv); + rettv->v_type = VAR_NUMBER; + rettv->vval.v_number = v; + } + else + { + semsg(_(e_blobidx), n1); + return FAIL; + } + } + return OK; +} + /* * "remove({blob})" function */ diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -4161,68 +4161,8 @@ eval_index_inner( break; case VAR_BLOB: - len = blob_len(rettv->vval.v_blob); - if (is_range) - { - // The resulting variable is a sub-blob. If the indexes - // are out of range the result is empty. - if (n1 < 0) - { - n1 = len + n1; - if (n1 < 0) - n1 = 0; - } - if (n2 < 0) - n2 = len + n2; - else if (n2 >= len) - n2 = len - (exclusive ? 0 : 1); - if (exclusive) - --n2; - if (n1 >= len || n2 < 0 || n1 > n2) - { - clear_tv(rettv); - rettv->v_type = VAR_BLOB; - rettv->vval.v_blob = NULL; - } - else - { - blob_T *blob = blob_alloc(); - long i; - - if (blob != NULL) - { - if (ga_grow(&blob->bv_ga, n2 - n1 + 1) == FAIL) - { - blob_free(blob); - return FAIL; - } - blob->bv_ga.ga_len = n2 - n1 + 1; - for (i = n1; i <= n2; i++) - blob_set(blob, i - n1, - blob_get(rettv->vval.v_blob, i)); - - clear_tv(rettv); - rettv_blob_set(rettv, blob); - } - } - } - else - { - // The resulting variable is a byte value. - // If the index is too big or negative that is an error. - if (n1 < 0) - n1 = len + n1; - if (n1 < len && n1 >= 0) - { - int v = blob_get(rettv->vval.v_blob, n1); - - clear_tv(rettv); - rettv->v_type = VAR_NUMBER; - rettv->vval.v_number = v; - } - else - semsg(_(e_blobidx), n1); - } + blob_slice_or_index(rettv->vval.v_blob, is_range, n1, n2, + exclusive, rettv); break; case VAR_LIST: diff --git a/src/proto/blob.pro b/src/proto/blob.pro --- a/src/proto/blob.pro +++ b/src/proto/blob.pro @@ -13,5 +13,6 @@ int read_blob(FILE *fd, blob_T *blob); int write_blob(FILE *fd, blob_T *blob); char_u *blob2string(blob_T *blob, char_u **tofree, char_u *numbuf); blob_T *string2blob(char_u *str); +int blob_slice_or_index(blob_T *blob, int is_range, varnumber_T n1, varnumber_T n2, int exclusive, typval_T *rettv); void blob_remove(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1622,6 +1622,26 @@ def Test_expr7_blob() assert_equal(g:blob_empty, 0z) assert_equal(g:blob_one, 0z01) assert_equal(g:blob_long, 0z0102.0304) + + var testblob = 0z010203 + assert_equal(0x01, testblob[0]) + assert_equal(0x02, testblob[1]) + assert_equal(0x03, testblob[-1]) + assert_equal(0x02, testblob[-2]) + + assert_equal(0z01, testblob[0 : 0]) + assert_equal(0z0102, testblob[0 : 1]) + assert_equal(0z010203, testblob[0 : 2]) + assert_equal(0z010203, testblob[0 : ]) + assert_equal(0z0203, testblob[1 : ]) + assert_equal(0z0203, testblob[1 : 2]) + assert_equal(0z0203, testblob[1 : -1]) + assert_equal(0z03, testblob[-1 : -1]) + assert_equal(0z02, testblob[-2 : -2]) + + # blob slice accepts out of range + assert_equal(0z, testblob[3 : 3]) + assert_equal(0z, testblob[0 : -4]) END CheckDefAndScriptSuccess(lines) diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 2756, +/**/ 2755, /**/ 2754, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -133,6 +133,8 @@ typedef enum { ISN_LISTAPPEND, // append to a list, like add() ISN_LISTINDEX, // [expr] list index ISN_LISTSLICE, // [expr:expr] list slice + ISN_BLOBINDEX, // [expr] blob index + ISN_BLOBSLICE, // [expr:expr] blob slice ISN_ANYINDEX, // [expr] runtime index ISN_ANYSLICE, // [expr:expr] runtime slice ISN_SLICE, // drop isn_arg.number items from start of list diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2725,8 +2725,18 @@ compile_member(int is_slice, cctx_T *cct } else if (vtype == VAR_BLOB) { - emsg("Sorry, blob index and slice not implemented yet"); - return FAIL; + if (is_slice) + { + *typep = &t_blob; + if (generate_instr_drop(cctx, ISN_BLOBSLICE, 2) == FAIL) + return FAIL; + } + else + { + *typep = &t_number; + if (generate_instr_drop(cctx, ISN_BLOBINDEX, 1) == FAIL) + return FAIL; + } } else if (vtype == VAR_LIST || *typep == &t_any) { @@ -4088,7 +4098,7 @@ compile_subscript( // list index: list[123] // dict member: dict[key] // string index: text[123] - // TODO: blob index + // blob index: blob[123] // TODO: more arguments // TODO: recognize list or dict at runtime if (generate_ppconst(cctx, ppconst) == FAIL) @@ -9241,6 +9251,8 @@ delete_instr(isn_T *isn) case ISN_ANYSLICE: case ISN_BCALL: case ISN_BLOBAPPEND: + case ISN_BLOBINDEX: + case ISN_BLOBSLICE: case ISN_CATCH: case ISN_CHECKLEN: case ISN_CHECKNR: diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -3415,16 +3415,21 @@ call_def_function( case ISN_LISTINDEX: case ISN_LISTSLICE: + case ISN_BLOBINDEX: + case ISN_BLOBSLICE: { - int is_slice = iptr->isn_type == ISN_LISTSLICE; - list_T *list; + int is_slice = iptr->isn_type == ISN_LISTSLICE + || iptr->isn_type == ISN_BLOBSLICE; + int is_blob = iptr->isn_type == ISN_BLOBINDEX + || iptr->isn_type == ISN_BLOBSLICE; varnumber_T n1, n2; + typval_T *val_tv; // list index: list is at stack-2, index at stack-1 // list slice: list is at stack-3, indexes at stack-2 and // stack-1 - tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2); - list = tv->vval.v_list; + // Same for blob. + val_tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2); tv = STACK_TV_BOT(-1); n1 = n2 = tv->vval.v_number; @@ -3440,9 +3445,18 @@ call_def_function( ectx.ec_stack.ga_len -= is_slice ? 2 : 1; tv = STACK_TV_BOT(-1); SOURCING_LNUM = iptr->isn_lnum; - if (list_slice_or_index(list, is_slice, n1, n2, FALSE, - tv, TRUE) == FAIL) - goto on_error; + if (is_blob) + { + if (blob_slice_or_index(val_tv->vval.v_blob, is_slice, + n1, n2, FALSE, tv) == FAIL) + goto on_error; + } + else + { + if (list_slice_or_index(val_tv->vval.v_list, is_slice, + n1, n2, FALSE, tv, TRUE) == FAIL) + goto on_error; + } } break; @@ -4688,6 +4702,8 @@ ex_disassemble(exarg_T *eap) case ISN_CONCAT: smsg("%4d CONCAT", current); break; case ISN_STRINDEX: smsg("%4d STRINDEX", current); break; case ISN_STRSLICE: smsg("%4d STRSLICE", current); break; + case ISN_BLOBINDEX: smsg("%4d BLOBINDEX", current); break; + case ISN_BLOBSLICE: smsg("%4d BLOBSLICE", current); break; case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break; case ISN_BLOBAPPEND: smsg("%4d BLOBAPPEND", current); break; case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;