changeset 24432:aa150abca273 v8.2.2756

patch 8.2.2756: Vim9: blob index and slice not implemented yet Commit: https://github.com/vim/vim/commit/cfc3023cb6ce5aaec13f49bc4b821feb05e3fb03 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Sun, 11 Apr 2021 20:30:04 +0200
parents 8f23b64d87fa
children a1e1e1eaa09b
files src/blob.c src/eval.c src/proto/blob.pro src/testdir/test_vim9_expr.vim src/version.c src/vim9.h src/vim9compile.c src/vim9execute.c
diffstat 8 files changed, 142 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- 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
  */
--- 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:
--- 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 : */
--- 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)
 
--- 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,
--- 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
--- 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:
--- 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;