summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/errors.h2
-rw-r--r--src/testdir/test_vim9_disassemble.vim30
-rw-r--r--src/testdir/test_vim9_func.vim18
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h5
-rw-r--r--src/vim9compile.c47
-rw-r--r--src/vim9execute.c22
7 files changed, 122 insertions, 4 deletions
diff --git a/src/errors.h b/src/errors.h
index 664bcd9325..8ddf441573 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -282,4 +282,6 @@ EXTERN char e_endblock_without_block[]
INIT(= N_("E1128: } without {"));
EXTERN char e_throw_with_empty_string[]
INIT(= N_("E1129: Throw with empty string"));
+EXTERN char e_cannot_add_to_null_list[]
+ INIT(= N_("E1130: Cannot add to null list"));
#endif
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index 53bc4bad70..fe1ce66ec5 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -273,6 +273,34 @@ def Test_disassemble_list_assign()
res)
enddef
+def s:ListAdd()
+ var l: list<number> = []
+ add(l, 123)
+ add(l, g:aNumber)
+enddef
+
+def Test_disassemble_list_add()
+ var res = execute('disass s:ListAdd')
+ assert_match('<SNR>\d*_ListAdd\_s*' ..
+ 'var l: list<number> = []\_s*' ..
+ '\d NEWLIST size 0\_s*' ..
+ '\d STORE $0\_s*' ..
+ 'add(l, 123)\_s*' ..
+ '\d LOAD $0\_s*' ..
+ '\d PUSHNR 123\_s*' ..
+ '\d LISTAPPEND\_s*' ..
+ '\d DROP\_s*' ..
+ 'add(l, g:aNumber)\_s*' ..
+ '\d LOAD $0\_s*' ..
+ '\d\+ LOADG g:aNumber\_s*' ..
+ '\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
+ '\d\+ LISTAPPEND\_s*' ..
+ '\d\+ DROP\_s*' ..
+ '\d\+ PUSHNR 0\_s*' ..
+ '\d\+ RETURN',
+ res)
+enddef
+
def s:ScriptFuncUnlet()
g:somevar = "value"
unlet g:somevar
@@ -803,7 +831,7 @@ def Test_disassemble_for_loop()
'res->add(i)\_s*' ..
'\d LOAD $0\_s*' ..
'\d LOAD $2\_s*' ..
- '\d\+ BCALL add(argc 2)\_s*' ..
+ '\d\+ LISTAPPEND\_s*' ..
'\d\+ DROP\_s*' ..
'endfor\_s*' ..
'\d\+ JUMP -> \d\+\_s*' ..
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index cc6af6a86a..bded91f784 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -1772,6 +1772,24 @@ def Test_list2str_str2list_utf8()
list2str(l, true)->assert_equal(s)
enddef
+def Test_list_add()
+ var l: list<number> # defaults to empty list
+ add(l, 9)
+ assert_equal([9], l)
+
+ var lines =<< trim END
+ var l: list<number>
+ add(l, "x")
+ END
+ CheckDefFailure(lines, 'E1012:', 2)
+
+ lines =<< trim END
+ var l: list<number> = test_null_list()
+ add(l, 123)
+ END
+ CheckDefExecFailure(lines, 'E1130:', 2)
+enddef
+
def SID(): number
return expand('<SID>')
->matchstr('<SNR>\zs\d\+\ze_$')
diff --git a/src/version.c b/src/version.c
index ef5ea876f5..2894dedb8c 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 */
/**/
+ 1865,
+/**/
1864,
/**/
1863,
diff --git a/src/vim9.h b/src/vim9.h
index 537e3abe08..4cece6d814 100644
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -96,8 +96,8 @@ typedef enum {
ISN_ENDTRY, // take entry off from ec_trystack
// more expression operations
- ISN_ADDLIST,
- ISN_ADDBLOB,
+ ISN_ADDLIST, // add two lists
+ ISN_ADDBLOB, // add two blobs
// operation with two arguments; isn_arg.op.op_type is exptype_T
ISN_OPNR,
@@ -120,6 +120,7 @@ typedef enum {
ISN_CONCAT,
ISN_STRINDEX, // [expr] string index
ISN_STRSLICE, // [expr:expr] string slice
+ ISN_LISTAPPEND, // append to a list, like add()
ISN_LISTINDEX, // [expr] list index
ISN_LISTSLICE, // [expr:expr] list slice
ISN_ANYINDEX, // [expr] runtime index
diff --git a/src/vim9compile.c b/src/vim9compile.c
index a891006f97..bb4807eeb7 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1495,6 +1495,32 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount, int method_call)
}
/*
+ * Generate an ISN_LISTAPPEND instruction. Works like add().
+ * Argument count is already checked.
+ */
+ static int
+generate_LISTAPPEND(cctx_T *cctx)
+{
+ garray_T *stack = &cctx->ctx_type_stack;
+ type_T *list_type;
+ type_T *item_type;
+ type_T *expected;
+
+ // Caller already checked that list_type is a list.
+ list_type = ((type_T **)stack->ga_data)[stack->ga_len - 2];
+ item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+ expected = list_type->tt_member;
+ if (need_type(item_type, expected, -1, cctx, FALSE, FALSE) == FAIL)
+ return FAIL;
+
+ if (generate_instr(cctx, ISN_LISTAPPEND) == NULL)
+ return FAIL;
+
+ --stack->ga_len; // drop the argument
+ return OK;
+}
+
+/*
* Generate an ISN_DCALL or ISN_UCALL instruction.
* Return FAIL if the number of arguments is wrong.
*/
@@ -2537,7 +2563,25 @@ compile_call(
// builtin function
idx = find_internal_func(name);
if (idx >= 0)
- res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
+ {
+ if (STRCMP(name, "add") == 0 && argcount == 2)
+ {
+ garray_T *stack = &cctx->ctx_type_stack;
+ type_T *type = ((type_T **)stack->ga_data)[
+ stack->ga_len - 2];
+
+ // TODO: also check for VAR_BLOB
+ if (type->tt_type == VAR_LIST)
+ {
+ // inline "add(list, item)" so that the type can be checked
+ res = generate_LISTAPPEND(cctx);
+ idx = -1;
+ }
+ }
+
+ if (idx >= 0)
+ res = generate_BCALL(cctx, idx, argcount, argcount_init == 1);
+ }
else
semsg(_(e_unknownfunc), namebuf);
goto theend;
@@ -7656,6 +7700,7 @@ delete_instr(isn_T *isn)
case ISN_FOR:
case ISN_GETITEM:
case ISN_JUMP:
+ case ISN_LISTAPPEND:
case ISN_LISTINDEX:
case ISN_LISTSLICE:
case ISN_LOAD:
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 673bf91c43..031761d422 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -2095,6 +2095,7 @@ call_def_function(
|| *skipwhite(tv->vval.v_string) == NUL)
{
vim_free(tv->vval.v_string);
+ SOURCING_LNUM = iptr->isn_lnum;
emsg(_(e_throw_with_empty_string));
goto failed;
}
@@ -2282,6 +2283,7 @@ call_def_function(
typval_T *tv1 = STACK_TV_BOT(-2);
typval_T *tv2 = STACK_TV_BOT(-1);
+ // add two lists or blobs
if (iptr->isn_type == ISN_ADDLIST)
eval_addlist(tv1, tv2);
else
@@ -2291,6 +2293,25 @@ call_def_function(
}
break;
+ case ISN_LISTAPPEND:
+ {
+ typval_T *tv1 = STACK_TV_BOT(-2);
+ typval_T *tv2 = STACK_TV_BOT(-1);
+ list_T *l = tv1->vval.v_list;
+
+ // add an item to a list
+ if (l == NULL)
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ emsg(_(e_cannot_add_to_null_list));
+ goto on_error;
+ }
+ if (list_append_tv(l, tv2) == FAIL)
+ goto failed;
+ --ectx.ec_stack.ga_len;
+ }
+ break;
+
// Computation with two arguments of unknown type
case ISN_OPANY:
{
@@ -3410,6 +3431,7 @@ 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_LISTAPPEND: smsg("%4d LISTAPPEND", current); break;
case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;