Problem: Vim9: blob index and slice not implemented yet.
Solution: Implement blob index and slice.
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
*/
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:
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 : */
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)
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2756,
/**/
2755,
/**/
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
}
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)
{
// 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)
case ISN_ANYSLICE:
case ISN_BCALL:
case ISN_BLOBAPPEND:
+ case ISN_BLOBINDEX:
+ case ISN_BLOBSLICE:
case ISN_CATCH:
case ISN_CHECKLEN:
case ISN_CHECKNR:
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;
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;
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;