1
0
forked from aniani/vim

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.
This commit is contained in:
Bram Moolenaar 2021-04-11 20:26:34 +02:00
parent af8ea0d066
commit cfc3023cb6
8 changed files with 142 additions and 72 deletions

View File

@ -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
*/

View File

@ -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:

View File

@ -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 : */

View File

@ -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)

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2756,
/**/
2755,
/**/

View File

@ -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

View File

@ -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:

View File

@ -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;