summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-04-11 20:26:34 +0200
committerBram Moolenaar <Bram@vim.org>2021-04-11 20:26:34 +0200
commitcfc3023cb6ce5aaec13f49bc4b821feb05e3fb03 (patch)
treeda16e23aca547d7eb0cf4c4026415fad30d5b00f
parentaf8ea0d066d31cf3cd0a39c5c49ce0342728588d (diff)
patch 8.2.2756: Vim9: blob index and slice not implemented yetv8.2.2756
Problem: Vim9: blob index and slice not implemented yet. Solution: Implement blob index and slice.
-rw-r--r--src/blob.c77
-rw-r--r--src/eval.c64
-rw-r--r--src/proto/blob.pro1
-rw-r--r--src/testdir/test_vim9_expr.vim20
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h2
-rw-r--r--src/vim9compile.c18
-rw-r--r--src/vim9execute.c30
8 files changed, 142 insertions, 72 deletions
diff --git a/src/blob.c b/src/blob.c
index 264962e197..8d260f172b 100644
--- 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
index 787243ed65..1291b364a9 100644
--- 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
index 3bc6625456..6be7f0bea5 100644
--- 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
index 0e0e34e01e..456b42612e 100644
--- 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
index d8b39eb226..0dc382f43b 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 */
/**/
+ 2756,
+/**/
2755,
/**/
2754,
diff --git a/src/vim9.h b/src/vim9.h
index 0c8a949e87..c30e597adb 100644
--- 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
index 59d1339073..9263659640 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2725,8 +2725,18 @@ compile_member(int is_slice, cctx_T *cctx)
}
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
index 017d5774ef..94d6f45232 100644
--- 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;