mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.1867: Vim9: argument to add() not checked for blob
Problem: Vim9: argument to add() not checked for blob. Solution: Add the BLOBAPPEND instruction.
This commit is contained in:
parent
66fa5fd54f
commit
80b0e5ea11
@ -284,4 +284,6 @@ EXTERN char e_throw_with_empty_string[]
|
|||||||
INIT(= N_("E1129: Throw with empty string"));
|
INIT(= N_("E1129: Throw with empty string"));
|
||||||
EXTERN char e_cannot_add_to_null_list[]
|
EXTERN char e_cannot_add_to_null_list[]
|
||||||
INIT(= N_("E1130: Cannot add to null list"));
|
INIT(= N_("E1130: Cannot add to null list"));
|
||||||
|
EXTERN char e_cannot_add_to_null_blob[]
|
||||||
|
INIT(= N_("E1131: Cannot add to null blob"));
|
||||||
#endif
|
#endif
|
||||||
|
@ -301,6 +301,34 @@ def Test_disassemble_list_add()
|
|||||||
res)
|
res)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def s:BlobAdd()
|
||||||
|
var b: blob = 0z
|
||||||
|
add(b, 123)
|
||||||
|
add(b, g:aNumber)
|
||||||
|
enddef
|
||||||
|
|
||||||
|
def Test_disassemble_blob_add()
|
||||||
|
var res = execute('disass s:BlobAdd')
|
||||||
|
assert_match('<SNR>\d*_BlobAdd\_s*' ..
|
||||||
|
'var b: blob = 0z\_s*' ..
|
||||||
|
'\d PUSHBLOB 0z\_s*' ..
|
||||||
|
'\d STORE $0\_s*' ..
|
||||||
|
'add(b, 123)\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d PUSHNR 123\_s*' ..
|
||||||
|
'\d BLOBAPPEND\_s*' ..
|
||||||
|
'\d DROP\_s*' ..
|
||||||
|
'add(b, g:aNumber)\_s*' ..
|
||||||
|
'\d LOAD $0\_s*' ..
|
||||||
|
'\d\+ LOADG g:aNumber\_s*' ..
|
||||||
|
'\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
|
||||||
|
'\d\+ BLOBAPPEND\_s*' ..
|
||||||
|
'\d\+ DROP\_s*' ..
|
||||||
|
'\d\+ PUSHNR 0\_s*' ..
|
||||||
|
'\d\+ RETURN',
|
||||||
|
res)
|
||||||
|
enddef
|
||||||
|
|
||||||
def s:ScriptFuncUnlet()
|
def s:ScriptFuncUnlet()
|
||||||
g:somevar = "value"
|
g:somevar = "value"
|
||||||
unlet g:somevar
|
unlet g:somevar
|
||||||
|
@ -1791,9 +1791,25 @@ def Test_list_add()
|
|||||||
enddef
|
enddef
|
||||||
|
|
||||||
def Test_blob_add()
|
def Test_blob_add()
|
||||||
var b: blob = 0z12
|
var b1: blob = 0z12
|
||||||
add(b, 0x34)
|
add(b1, 0x34)
|
||||||
assert_equal(0z1234, b)
|
assert_equal(0z1234, b1)
|
||||||
|
|
||||||
|
var b2: blob # defaults to empty blob
|
||||||
|
add(b2, 0x67)
|
||||||
|
assert_equal(0z67, b2)
|
||||||
|
|
||||||
|
var lines =<< trim END
|
||||||
|
var b: blob
|
||||||
|
add(b, "x")
|
||||||
|
END
|
||||||
|
CheckDefFailure(lines, 'E1012:', 2)
|
||||||
|
|
||||||
|
lines =<< trim END
|
||||||
|
var b: blob = test_null_blob()
|
||||||
|
add(b, 123)
|
||||||
|
END
|
||||||
|
CheckDefExecFailure(lines, 'E1131:', 2)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
def SID(): number
|
def SID(): number
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1867,
|
||||||
/**/
|
/**/
|
||||||
1866,
|
1866,
|
||||||
/**/
|
/**/
|
||||||
|
@ -126,6 +126,7 @@ typedef enum {
|
|||||||
ISN_ANYINDEX, // [expr] runtime index
|
ISN_ANYINDEX, // [expr] runtime index
|
||||||
ISN_ANYSLICE, // [expr:expr] runtime slice
|
ISN_ANYSLICE, // [expr:expr] runtime slice
|
||||||
ISN_SLICE, // drop isn_arg.number items from start of list
|
ISN_SLICE, // drop isn_arg.number items from start of list
|
||||||
|
ISN_BLOBAPPEND, // append to a blob, like add()
|
||||||
ISN_GETITEM, // push list item, isn_arg.number is the index
|
ISN_GETITEM, // push list item, isn_arg.number is the index
|
||||||
ISN_MEMBER, // dict[member]
|
ISN_MEMBER, // dict[member]
|
||||||
ISN_STRINGMEMBER, // dict.member using isn_arg.string
|
ISN_STRINGMEMBER, // dict.member using isn_arg.string
|
||||||
|
@ -1520,6 +1520,28 @@ generate_LISTAPPEND(cctx_T *cctx)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an ISN_BLOBAPPEND instruction. Works like add().
|
||||||
|
* Argument count is already checked.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
generate_BLOBAPPEND(cctx_T *cctx)
|
||||||
|
{
|
||||||
|
garray_T *stack = &cctx->ctx_type_stack;
|
||||||
|
type_T *item_type;
|
||||||
|
|
||||||
|
// Caller already checked that blob_type is a blob.
|
||||||
|
item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
|
||||||
|
if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
|
||||||
|
return FAIL;
|
||||||
|
|
||||||
|
--stack->ga_len; // drop the argument
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate an ISN_DCALL or ISN_UCALL instruction.
|
* Generate an ISN_DCALL or ISN_UCALL instruction.
|
||||||
* Return FAIL if the number of arguments is wrong.
|
* Return FAIL if the number of arguments is wrong.
|
||||||
@ -2570,13 +2592,18 @@ compile_call(
|
|||||||
type_T *type = ((type_T **)stack->ga_data)[
|
type_T *type = ((type_T **)stack->ga_data)[
|
||||||
stack->ga_len - 2];
|
stack->ga_len - 2];
|
||||||
|
|
||||||
// TODO: also check for VAR_BLOB
|
|
||||||
if (type->tt_type == VAR_LIST)
|
if (type->tt_type == VAR_LIST)
|
||||||
{
|
{
|
||||||
// inline "add(list, item)" so that the type can be checked
|
// inline "add(list, item)" so that the type can be checked
|
||||||
res = generate_LISTAPPEND(cctx);
|
res = generate_LISTAPPEND(cctx);
|
||||||
idx = -1;
|
idx = -1;
|
||||||
}
|
}
|
||||||
|
else if (type->tt_type == VAR_BLOB)
|
||||||
|
{
|
||||||
|
// inline "add(blob, nr)" so that the type can be checked
|
||||||
|
res = generate_BLOBAPPEND(cctx);
|
||||||
|
idx = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
@ -5421,7 +5448,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
|||||||
generate_PUSHS(cctx, NULL);
|
generate_PUSHS(cctx, NULL);
|
||||||
break;
|
break;
|
||||||
case VAR_BLOB:
|
case VAR_BLOB:
|
||||||
generate_PUSHBLOB(cctx, NULL);
|
generate_PUSHBLOB(cctx, blob_alloc());
|
||||||
break;
|
break;
|
||||||
case VAR_FUNC:
|
case VAR_FUNC:
|
||||||
generate_PUSHFUNC(cctx, NULL, &t_func_void);
|
generate_PUSHFUNC(cctx, NULL, &t_func_void);
|
||||||
@ -7675,6 +7702,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_ANYINDEX:
|
case ISN_ANYINDEX:
|
||||||
case ISN_ANYSLICE:
|
case ISN_ANYSLICE:
|
||||||
case ISN_BCALL:
|
case ISN_BCALL:
|
||||||
|
case ISN_BLOBAPPEND:
|
||||||
case ISN_CATCH:
|
case ISN_CATCH:
|
||||||
case ISN_CHECKLEN:
|
case ISN_CHECKLEN:
|
||||||
case ISN_CHECKNR:
|
case ISN_CHECKNR:
|
||||||
|
@ -2312,6 +2312,29 @@ call_def_function(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ISN_BLOBAPPEND:
|
||||||
|
{
|
||||||
|
typval_T *tv1 = STACK_TV_BOT(-2);
|
||||||
|
typval_T *tv2 = STACK_TV_BOT(-1);
|
||||||
|
blob_T *b = tv1->vval.v_blob;
|
||||||
|
int error = FALSE;
|
||||||
|
varnumber_T n;
|
||||||
|
|
||||||
|
// add a number to a blob
|
||||||
|
if (b == NULL)
|
||||||
|
{
|
||||||
|
SOURCING_LNUM = iptr->isn_lnum;
|
||||||
|
emsg(_(e_cannot_add_to_null_blob));
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
n = tv_get_number_chk(tv2, &error);
|
||||||
|
if (error)
|
||||||
|
goto on_error;
|
||||||
|
ga_append(&b->bv_ga, (int)n);
|
||||||
|
--ectx.ec_stack.ga_len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// Computation with two arguments of unknown type
|
// Computation with two arguments of unknown type
|
||||||
case ISN_OPANY:
|
case ISN_OPANY:
|
||||||
{
|
{
|
||||||
@ -3432,6 +3455,7 @@ ex_disassemble(exarg_T *eap)
|
|||||||
case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
|
case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
|
||||||
case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
|
case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
|
||||||
case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", 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;
|
case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
|
||||||
case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
|
case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
|
||||||
case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
|
case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user