mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.1466: Vim9: cannot index or slice a variable with type "any"
Problem: Vim9: cannot index or slice a variable with type "any". Solution: Add runtime index and slice.
This commit is contained in:
13
src/errors.h
13
src/errors.h
@@ -21,6 +21,10 @@ EXTERN char e_invalid_command[]
|
||||
#ifdef FEAT_EVAL
|
||||
EXTERN char e_invalid_command_str[]
|
||||
INIT(= N_("E476: Invalid command: %s"));
|
||||
EXTERN char e_cannot_slice_dictionary[]
|
||||
INIT(= N_("E719: cannot slice a Dictionary"));
|
||||
EXTERN char e_cannot_index_special_variable[]
|
||||
INIT(= N_("E909: Cannot index a special variable"));
|
||||
EXTERN char e_missing_let_str[]
|
||||
INIT(= N_("E1100: Missing :let: %s"));
|
||||
EXTERN char e_variable_not_found_str[]
|
||||
@@ -69,9 +73,9 @@ EXTERN char e_const_requires_a_value[]
|
||||
INIT(= N_("E1021: const requires a value"));
|
||||
EXTERN char e_type_or_initialization_required[]
|
||||
INIT(= N_("E1022: type or initialization required"));
|
||||
EXTERN char e_cannot_slice_dictionary[]
|
||||
INIT(= N_("E1023: cannot slice a dictionary"));
|
||||
// E1024 unused
|
||||
// E1023 unused
|
||||
EXTERN char e_using_number_as_string[]
|
||||
INIT(= N_("E1024: Using a Number as a String"));
|
||||
EXTERN char e_using_rcurly_outside_if_block_scope[]
|
||||
INIT(= N_("E1025: using } outside of a block scope"));
|
||||
EXTERN char e_missing_rcurly[]
|
||||
@@ -146,7 +150,8 @@ EXTERN char e_expected_dot_after_name_str[]
|
||||
INIT(= N_("E1060: expected dot after name: %s"));
|
||||
EXTERN char e_cannot_find_function_str[]
|
||||
INIT(= N_("E1061: Cannot find function %s"));
|
||||
// E1062 unused
|
||||
EXTERN char e_cannot_index_number[]
|
||||
INIT(= N_("E1062: Cannot index a Number"));
|
||||
EXTERN char e_type_mismatch_for_v_variable[]
|
||||
INIT(= N_("E1063: type mismatch for v: variable"));
|
||||
// E1064 unused
|
||||
|
210
src/eval.c
210
src/eval.c
@@ -20,8 +20,6 @@
|
||||
# include <float.h>
|
||||
#endif
|
||||
|
||||
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
|
||||
|
||||
#define NAMESPACE_CHAR (char_u *)"abglstvw"
|
||||
|
||||
/*
|
||||
@@ -928,7 +926,7 @@ get_lval(
|
||||
if (lp->ll_tv->v_type == VAR_DICT)
|
||||
{
|
||||
if (!quiet)
|
||||
emsg(_(e_dictrange));
|
||||
emsg(_(e_cannot_slice_dictionary));
|
||||
clear_tv(&var1);
|
||||
return NULL;
|
||||
}
|
||||
@@ -3549,47 +3547,12 @@ eval_index(
|
||||
&& (evalarg->eval_flags & EVAL_EVALUATE);
|
||||
int empty1 = FALSE, empty2 = FALSE;
|
||||
typval_T var1, var2;
|
||||
long i;
|
||||
long n1, n2 = 0;
|
||||
long len = -1;
|
||||
int range = FALSE;
|
||||
char_u *s;
|
||||
char_u *key = NULL;
|
||||
int keylen = -1;
|
||||
|
||||
switch (rettv->v_type)
|
||||
{
|
||||
case VAR_FUNC:
|
||||
case VAR_PARTIAL:
|
||||
if (verbose)
|
||||
emsg(_("E695: Cannot index a Funcref"));
|
||||
if (check_can_index(rettv, evaluate, verbose) == FAIL)
|
||||
return FAIL;
|
||||
case VAR_FLOAT:
|
||||
#ifdef FEAT_FLOAT
|
||||
if (verbose)
|
||||
emsg(_(e_float_as_string));
|
||||
return FAIL;
|
||||
#endif
|
||||
case VAR_BOOL:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
if (verbose)
|
||||
emsg(_("E909: Cannot index a special variable"));
|
||||
return FAIL;
|
||||
case VAR_UNKNOWN:
|
||||
case VAR_ANY:
|
||||
case VAR_VOID:
|
||||
if (evaluate)
|
||||
return FAIL;
|
||||
// FALLTHROUGH
|
||||
|
||||
case VAR_STRING:
|
||||
case VAR_NUMBER:
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_BLOB:
|
||||
break;
|
||||
}
|
||||
|
||||
init_tv(&var1);
|
||||
init_tv(&var2);
|
||||
@@ -3599,11 +3562,11 @@ eval_index(
|
||||
* dict.name
|
||||
*/
|
||||
key = *arg + 1;
|
||||
for (len = 0; eval_isdictc(key[len]); ++len)
|
||||
for (keylen = 0; eval_isdictc(key[keylen]); ++keylen)
|
||||
;
|
||||
if (len == 0)
|
||||
if (keylen == 0)
|
||||
return FAIL;
|
||||
*arg = skipwhite(key + len);
|
||||
*arg = skipwhite(key + keylen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3666,21 +3629,102 @@ eval_index(
|
||||
|
||||
if (evaluate)
|
||||
{
|
||||
n1 = 0;
|
||||
if (!empty1 && rettv->v_type != VAR_DICT)
|
||||
{
|
||||
n1 = tv_get_number(&var1);
|
||||
int res = eval_index_inner(rettv, range,
|
||||
empty1 ? NULL : &var1, empty2 ? NULL : &var2,
|
||||
key, keylen, verbose);
|
||||
if (!empty1)
|
||||
clear_tv(&var1);
|
||||
}
|
||||
if (range)
|
||||
clear_tv(&var2);
|
||||
return res;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if "rettv" can have an [index] or [sli:ce]
|
||||
*/
|
||||
int
|
||||
check_can_index(typval_T *rettv, int evaluate, int verbose)
|
||||
{
|
||||
switch (rettv->v_type)
|
||||
{
|
||||
if (empty2)
|
||||
case VAR_FUNC:
|
||||
case VAR_PARTIAL:
|
||||
if (verbose)
|
||||
emsg(_("E695: Cannot index a Funcref"));
|
||||
return FAIL;
|
||||
case VAR_FLOAT:
|
||||
#ifdef FEAT_FLOAT
|
||||
if (verbose)
|
||||
emsg(_(e_float_as_string));
|
||||
return FAIL;
|
||||
#endif
|
||||
case VAR_BOOL:
|
||||
case VAR_SPECIAL:
|
||||
case VAR_JOB:
|
||||
case VAR_CHANNEL:
|
||||
if (verbose)
|
||||
emsg(_(e_cannot_index_special_variable));
|
||||
return FAIL;
|
||||
case VAR_UNKNOWN:
|
||||
case VAR_ANY:
|
||||
case VAR_VOID:
|
||||
if (evaluate)
|
||||
{
|
||||
emsg(_(e_cannot_index_special_variable));
|
||||
return FAIL;
|
||||
}
|
||||
// FALLTHROUGH
|
||||
|
||||
case VAR_STRING:
|
||||
case VAR_LIST:
|
||||
case VAR_DICT:
|
||||
case VAR_BLOB:
|
||||
break;
|
||||
case VAR_NUMBER:
|
||||
if (in_vim9script())
|
||||
emsg(_(e_cannot_index_number));
|
||||
break;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply index or range to "rettv".
|
||||
* "var1" is the first index, NULL for [:expr].
|
||||
* "var2" is the second index, NULL for [expr] and [expr: ]
|
||||
* Alternatively, "key" is not NULL, then key[keylen] is the dict index.
|
||||
*/
|
||||
int
|
||||
eval_index_inner(
|
||||
typval_T *rettv,
|
||||
int is_range,
|
||||
typval_T *var1,
|
||||
typval_T *var2,
|
||||
char_u *key,
|
||||
int keylen,
|
||||
int verbose)
|
||||
{
|
||||
long n1, n2 = 0;
|
||||
long len;
|
||||
|
||||
n1 = 0;
|
||||
if (var1 != NULL && rettv->v_type != VAR_DICT)
|
||||
n1 = tv_get_number(var1);
|
||||
|
||||
if (is_range)
|
||||
{
|
||||
if (rettv->v_type == VAR_DICT)
|
||||
{
|
||||
if (verbose)
|
||||
emsg(_(e_cannot_slice_dictionary));
|
||||
return FAIL;
|
||||
}
|
||||
if (var2 == NULL)
|
||||
n2 = -1;
|
||||
else
|
||||
{
|
||||
n2 = tv_get_number(&var2);
|
||||
clear_tv(&var2);
|
||||
}
|
||||
n2 = tv_get_number(var2);
|
||||
}
|
||||
|
||||
switch (rettv->v_type)
|
||||
@@ -3699,16 +3743,18 @@ eval_index(
|
||||
|
||||
case VAR_NUMBER:
|
||||
case VAR_STRING:
|
||||
s = tv_get_string(rettv);
|
||||
{
|
||||
char_u *s = tv_get_string(rettv);
|
||||
|
||||
len = (long)STRLEN(s);
|
||||
if (in_vim9script())
|
||||
{
|
||||
if (range)
|
||||
if (is_range)
|
||||
s = string_slice(s, n1, n2);
|
||||
else
|
||||
s = char_from_string(s, n1);
|
||||
}
|
||||
else if (range)
|
||||
else if (is_range)
|
||||
{
|
||||
// The resulting variable is a substring. If the indexes
|
||||
// are out of range the result is empty.
|
||||
@@ -3740,11 +3786,12 @@ eval_index(
|
||||
clear_tv(rettv);
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = s;
|
||||
}
|
||||
break;
|
||||
|
||||
case VAR_BLOB:
|
||||
len = blob_len(rettv->vval.v_blob);
|
||||
if (range)
|
||||
if (is_range)
|
||||
{
|
||||
// The resulting variable is a sub-blob. If the indexes
|
||||
// are out of range the result is empty.
|
||||
@@ -3767,6 +3814,7 @@ eval_index(
|
||||
else
|
||||
{
|
||||
blob_T *blob = blob_alloc();
|
||||
long i;
|
||||
|
||||
if (blob != NULL)
|
||||
{
|
||||
@@ -3805,54 +3853,40 @@ eval_index(
|
||||
break;
|
||||
|
||||
case VAR_LIST:
|
||||
if (empty1)
|
||||
if (var1 == NULL)
|
||||
n1 = 0;
|
||||
if (empty2)
|
||||
if (var2 == NULL)
|
||||
n2 = -1;
|
||||
if (list_slice_or_index(rettv->vval.v_list,
|
||||
range, n1, n2, rettv, verbose) == FAIL)
|
||||
is_range, n1, n2, rettv, verbose) == FAIL)
|
||||
return FAIL;
|
||||
break;
|
||||
|
||||
case VAR_DICT:
|
||||
if (range)
|
||||
{
|
||||
if (verbose)
|
||||
emsg(_(e_dictrange));
|
||||
if (len == -1)
|
||||
clear_tv(&var1);
|
||||
return FAIL;
|
||||
}
|
||||
{
|
||||
dictitem_T *item;
|
||||
typval_T tmp;
|
||||
|
||||
if (len == -1)
|
||||
{
|
||||
key = tv_get_string_chk(&var1);
|
||||
if (key == NULL)
|
||||
{
|
||||
clear_tv(&var1);
|
||||
key = tv_get_string_chk(var1);
|
||||
if (key == NULL)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
item = dict_find(rettv->vval.v_dict, key, (int)len);
|
||||
item = dict_find(rettv->vval.v_dict, key, (int)keylen);
|
||||
|
||||
if (item == NULL && verbose)
|
||||
semsg(_(e_dictkey), key);
|
||||
if (len == -1)
|
||||
clear_tv(&var1);
|
||||
if (item == NULL)
|
||||
return FAIL;
|
||||
|
||||
copy_tv(&item->di_tv, &var1);
|
||||
copy_tv(&item->di_tv, &tmp);
|
||||
clear_tv(rettv);
|
||||
*rettv = var1;
|
||||
*rettv = tmp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -5292,9 +5326,9 @@ char_from_string(char_u *str, varnumber_T index)
|
||||
* "str_len".
|
||||
* If going over the end return "str_len".
|
||||
* If "idx" is negative count from the end, -1 is the last character.
|
||||
* When going over the start return zero.
|
||||
* When going over the start return -1.
|
||||
*/
|
||||
static size_t
|
||||
static long
|
||||
char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
|
||||
{
|
||||
varnumber_T nchar = idx;
|
||||
@@ -5317,8 +5351,10 @@ char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
|
||||
nbyte -= mb_head_off(str, str + nbyte);
|
||||
++nchar;
|
||||
}
|
||||
if (nchar < 0)
|
||||
return -1;
|
||||
}
|
||||
return nbyte;
|
||||
return (long)nbyte;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -5328,24 +5364,26 @@ char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
|
||||
char_u *
|
||||
string_slice(char_u *str, varnumber_T first, varnumber_T last)
|
||||
{
|
||||
size_t start_byte, end_byte;
|
||||
long start_byte, end_byte;
|
||||
size_t slen;
|
||||
|
||||
if (str == NULL)
|
||||
return NULL;
|
||||
slen = STRLEN(str);
|
||||
start_byte = char_idx2byte(str, slen, first);
|
||||
if (start_byte < 0)
|
||||
start_byte = 0; // first index very negative: use zero
|
||||
if (last == -1)
|
||||
end_byte = slen;
|
||||
else
|
||||
{
|
||||
end_byte = char_idx2byte(str, slen, last);
|
||||
if (end_byte < slen)
|
||||
if (end_byte >= 0 && end_byte < (long)slen)
|
||||
// end index is inclusive
|
||||
end_byte += MB_CPTR2LEN(str + end_byte);
|
||||
}
|
||||
|
||||
if (start_byte >= slen || end_byte <= start_byte)
|
||||
if (start_byte >= (long)slen || end_byte <= start_byte)
|
||||
return NULL;
|
||||
return vim_strnsave(str + start_byte, end_byte - start_byte);
|
||||
}
|
||||
|
@@ -914,7 +914,7 @@ list_slice_or_index(
|
||||
semsg(_(e_listidx), n1);
|
||||
return FAIL;
|
||||
}
|
||||
n1 = len;
|
||||
n1 = n1 < 0 ? 0 : len;
|
||||
}
|
||||
if (range)
|
||||
{
|
||||
|
@@ -37,6 +37,8 @@ int eval0(char_u *arg, typval_T *rettv, exarg_T *eap, evalarg_T *evalarg);
|
||||
int eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
|
||||
void eval_addblob(typval_T *tv1, typval_T *tv2);
|
||||
int eval_addlist(typval_T *tv1, typval_T *tv2);
|
||||
int check_can_index(typval_T *rettv, int evaluate, int verbose);
|
||||
int eval_index_inner(typval_T *rettv, int is_range, typval_T *var1, typval_T *var2, char_u *key, int keylen, int verbose);
|
||||
char_u *partial_name(partial_T *pt);
|
||||
void partial_unref(partial_T *pt);
|
||||
int get_copyID(void);
|
||||
|
@@ -1091,6 +1091,50 @@ def Test_disassemble_dict_member()
|
||||
call assert_equal(1, DictMember())
|
||||
enddef
|
||||
|
||||
let somelist = [1, 2, 3, 4, 5]
|
||||
def AnyIndex(): number
|
||||
let res = g:somelist[2]
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_disassemble_any_index()
|
||||
let instr = execute('disassemble AnyIndex')
|
||||
assert_match('AnyIndex\_s*' ..
|
||||
'let res = g:somelist\[2\]\_s*' ..
|
||||
'\d LOADG g:somelist\_s*' ..
|
||||
'\d PUSHNR 2\_s*' ..
|
||||
'\d ANYINDEX\_s*' ..
|
||||
'\d STORE $0\_s*' ..
|
||||
'return res\_s*' ..
|
||||
'\d LOAD $0\_s*' ..
|
||||
'\d CHECKTYPE number stack\[-1\]\_s*' ..
|
||||
'\d RETURN',
|
||||
instr)
|
||||
assert_equal(3, AnyIndex())
|
||||
enddef
|
||||
|
||||
def AnySlice(): list<number>
|
||||
let res = g:somelist[1:3]
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_disassemble_any_slice()
|
||||
let instr = execute('disassemble AnySlice')
|
||||
assert_match('AnySlice\_s*' ..
|
||||
'let res = g:somelist\[1:3\]\_s*' ..
|
||||
'\d LOADG g:somelist\_s*' ..
|
||||
'\d PUSHNR 1\_s*' ..
|
||||
'\d PUSHNR 3\_s*' ..
|
||||
'\d ANYSLICE\_s*' ..
|
||||
'\d STORE $0\_s*' ..
|
||||
'return res\_s*' ..
|
||||
'\d LOAD $0\_s*' ..
|
||||
'\d CHECKTYPE list stack\[-1\]\_s*' ..
|
||||
'\d RETURN',
|
||||
instr)
|
||||
assert_equal([2, 3, 4], AnySlice())
|
||||
enddef
|
||||
|
||||
def NegateNumber(): number
|
||||
let nr = 9
|
||||
let plus = +nr
|
||||
|
@@ -1457,7 +1457,7 @@ def Test_expr7_list()
|
||||
4]
|
||||
|
||||
call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
|
||||
call CheckDefExecFailure(["let x = g:anint[3]"], 'E1029:')
|
||||
call CheckDefExecFailure(["let x = g:anint[3]"], 'E1062:')
|
||||
|
||||
call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
|
||||
|
||||
@@ -1768,9 +1768,91 @@ def Test_expr_member()
|
||||
call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1029: Expected dict but got list')
|
||||
enddef
|
||||
|
||||
def Test_expr_index()
|
||||
def Test_expr7_any_index_slice()
|
||||
let lines =<< trim END
|
||||
# getting the one member should clear the list only after getting the item
|
||||
assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
|
||||
|
||||
# string is permissive, index out of range accepted
|
||||
g:teststring = 'abcdef'
|
||||
assert_equal('b', g:teststring[1])
|
||||
assert_equal('', g:teststring[-1])
|
||||
assert_equal('', g:teststring[99])
|
||||
|
||||
assert_equal('b', g:teststring[1:1])
|
||||
assert_equal('bcdef', g:teststring[1:])
|
||||
assert_equal('abcd', g:teststring[:3])
|
||||
assert_equal('cdef', g:teststring[-4:])
|
||||
assert_equal('abcdef', g:teststring[-9:])
|
||||
assert_equal('abcd', g:teststring[:-3])
|
||||
assert_equal('', g:teststring[:-9])
|
||||
|
||||
# blob index cannot be out of range
|
||||
g:testblob = 0z01ab
|
||||
assert_equal(0x01, g:testblob[0])
|
||||
assert_equal(0xab, g:testblob[1])
|
||||
assert_equal(0xab, g:testblob[-1])
|
||||
assert_equal(0x01, g:testblob[-2])
|
||||
|
||||
# blob slice accepts out of range
|
||||
assert_equal(0z01ab, g:testblob[0:1])
|
||||
assert_equal(0z01, g:testblob[0:0])
|
||||
assert_equal(0z01, g:testblob[-2:-2])
|
||||
assert_equal(0zab, g:testblob[1:1])
|
||||
assert_equal(0zab, g:testblob[-1:-1])
|
||||
assert_equal(0z, g:testblob[2:2])
|
||||
assert_equal(0z, g:testblob[0:-3])
|
||||
|
||||
# list index cannot be out of range
|
||||
g:testlist = [0, 1, 2, 3]
|
||||
assert_equal(0, g:testlist[0])
|
||||
assert_equal(1, g:testlist[1])
|
||||
assert_equal(3, g:testlist[3])
|
||||
assert_equal(3, g:testlist[-1])
|
||||
assert_equal(0, g:testlist[-4])
|
||||
assert_equal(1, g:testlist[g:theone])
|
||||
|
||||
# list slice accepts out of range
|
||||
assert_equal([0], g:testlist[0:0])
|
||||
assert_equal([3], g:testlist[3:3])
|
||||
assert_equal([0, 1], g:testlist[0:1])
|
||||
assert_equal([0, 1, 2, 3], g:testlist[0:3])
|
||||
assert_equal([0, 1, 2, 3], g:testlist[0:9])
|
||||
assert_equal([], g:testlist[-1:1])
|
||||
assert_equal([1], g:testlist[-3:1])
|
||||
assert_equal([0, 1], g:testlist[-4:1])
|
||||
assert_equal([0, 1], g:testlist[-9:1])
|
||||
assert_equal([1, 2, 3], g:testlist[1:-1])
|
||||
assert_equal([1], g:testlist[1:-3])
|
||||
assert_equal([], g:testlist[1:-4])
|
||||
assert_equal([], g:testlist[1:-9])
|
||||
|
||||
g:testdict = #{a: 1, b: 2}
|
||||
assert_equal(1, g:testdict['a'])
|
||||
assert_equal(2, g:testdict['b'])
|
||||
END
|
||||
|
||||
CheckDefSuccess(lines)
|
||||
CheckScriptSuccess(['vim9script'] + lines)
|
||||
|
||||
CheckDefExecFailure(['echo g:testblob[2]'], 'E979:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testblob[2]'], 'E979:')
|
||||
CheckDefExecFailure(['echo g:testblob[-3]'], 'E979:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testblob[-3]'], 'E979:')
|
||||
|
||||
CheckDefExecFailure(['echo g:testlist[4]'], 'E684:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testlist[4]'], 'E684:')
|
||||
CheckDefExecFailure(['echo g:testlist[-5]'], 'E684:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testlist[-5]'], 'E684:')
|
||||
|
||||
CheckDefExecFailure(['echo g:testdict["a":"b"]'], 'E719:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testdict["a":"b"]'], 'E719:')
|
||||
CheckDefExecFailure(['echo g:testdict[1]'], 'E716:')
|
||||
CheckScriptFailure(['vim9script', 'echo g:testdict[1]'], 'E716:')
|
||||
|
||||
unlet g:teststring
|
||||
unlet g:testblob
|
||||
unlet g:testlist
|
||||
enddef
|
||||
|
||||
def Test_expr_member_vim9script()
|
||||
|
@@ -793,8 +793,8 @@ def Test_try_catch()
|
||||
endtry
|
||||
assert_equal(99, n)
|
||||
|
||||
# TODO: this will change when index on "any" works
|
||||
try
|
||||
# string slice returns a string, not a number
|
||||
n = g:astring[3]
|
||||
catch /E1029:/
|
||||
n = 77
|
||||
|
@@ -754,6 +754,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1466,
|
||||
/**/
|
||||
1465,
|
||||
/**/
|
||||
|
@@ -120,6 +120,8 @@ typedef enum {
|
||||
ISN_STRSLICE, // [expr:expr] string slice
|
||||
ISN_LISTINDEX, // [expr] list index
|
||||
ISN_LISTSLICE, // [expr:expr] list slice
|
||||
ISN_ANYINDEX, // [expr] runtime index
|
||||
ISN_ANYSLICE, // [expr:expr] runtime slice
|
||||
ISN_SLICE, // drop isn_arg.number items from start of list
|
||||
ISN_GETITEM, // push list item, isn_arg.number is the index
|
||||
ISN_MEMBER, // dict[member]
|
||||
|
@@ -3179,20 +3179,20 @@ compile_subscript(
|
||||
}
|
||||
else if (vtype == VAR_LIST || *typep == &t_any)
|
||||
{
|
||||
// TODO: any requires runtime code
|
||||
if (*typep == &t_any && need_type(*typep, &t_list_any,
|
||||
is_slice ? -3 : -2, cctx, FALSE) == FAIL)
|
||||
return FAIL;
|
||||
if (is_slice)
|
||||
{
|
||||
if (generate_instr_drop(cctx, ISN_LISTSLICE, 2) == FAIL)
|
||||
if (generate_instr_drop(cctx,
|
||||
vtype == VAR_LIST ? ISN_LISTSLICE : ISN_ANYSLICE,
|
||||
2) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((*typep)->tt_type == VAR_LIST)
|
||||
*typep = (*typep)->tt_member;
|
||||
if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
|
||||
if (generate_instr_drop(cctx,
|
||||
vtype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX,
|
||||
1) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
@@ -7085,11 +7085,13 @@ delete_instr(isn_T *isn)
|
||||
case ISN_2STRING_ANY:
|
||||
case ISN_ADDBLOB:
|
||||
case ISN_ADDLIST:
|
||||
case ISN_ANYINDEX:
|
||||
case ISN_ANYSLICE:
|
||||
case ISN_BCALL:
|
||||
case ISN_CATCH:
|
||||
case ISN_CHECKLEN:
|
||||
case ISN_CHECKNR:
|
||||
case ISN_CHECKTYPE:
|
||||
case ISN_CHECKLEN:
|
||||
case ISN_COMPAREANY:
|
||||
case ISN_COMPAREBLOB:
|
||||
case ISN_COMPAREBOOL:
|
||||
@@ -7102,7 +7104,6 @@ delete_instr(isn_T *isn)
|
||||
case ISN_COMPARESTRING:
|
||||
case ISN_CONCAT:
|
||||
case ISN_DCALL:
|
||||
case ISN_SHUFFLE:
|
||||
case ISN_DROP:
|
||||
case ISN_ECHO:
|
||||
case ISN_ECHOERR:
|
||||
@@ -7111,14 +7112,10 @@ delete_instr(isn_T *isn)
|
||||
case ISN_EXECCONCAT:
|
||||
case ISN_EXECUTE:
|
||||
case ISN_FOR:
|
||||
case ISN_GETITEM:
|
||||
case ISN_JUMP:
|
||||
case ISN_LISTINDEX:
|
||||
case ISN_LISTSLICE:
|
||||
case ISN_STRINDEX:
|
||||
case ISN_STRSLICE:
|
||||
case ISN_GETITEM:
|
||||
case ISN_SLICE:
|
||||
case ISN_MEMBER:
|
||||
case ISN_JUMP:
|
||||
case ISN_LOAD:
|
||||
case ISN_LOADBDICT:
|
||||
case ISN_LOADGDICT:
|
||||
@@ -7128,27 +7125,32 @@ delete_instr(isn_T *isn)
|
||||
case ISN_LOADTDICT:
|
||||
case ISN_LOADV:
|
||||
case ISN_LOADWDICT:
|
||||
case ISN_MEMBER:
|
||||
case ISN_NEGATENR:
|
||||
case ISN_NEWDICT:
|
||||
case ISN_NEWLIST:
|
||||
case ISN_OPNR:
|
||||
case ISN_OPFLOAT:
|
||||
case ISN_OPANY:
|
||||
case ISN_OPFLOAT:
|
||||
case ISN_OPNR:
|
||||
case ISN_PCALL:
|
||||
case ISN_PCALL_END:
|
||||
case ISN_PUSHBOOL:
|
||||
case ISN_PUSHF:
|
||||
case ISN_PUSHNR:
|
||||
case ISN_PUSHBOOL:
|
||||
case ISN_PUSHSPEC:
|
||||
case ISN_RETURN:
|
||||
case ISN_SHUFFLE:
|
||||
case ISN_SLICE:
|
||||
case ISN_STORE:
|
||||
case ISN_STOREOUTER:
|
||||
case ISN_STOREV:
|
||||
case ISN_STORENR:
|
||||
case ISN_STOREREG:
|
||||
case ISN_STORESCRIPT:
|
||||
case ISN_STOREDICT:
|
||||
case ISN_STORELIST:
|
||||
case ISN_STORENR:
|
||||
case ISN_STOREOUTER:
|
||||
case ISN_STOREREG:
|
||||
case ISN_STORESCRIPT:
|
||||
case ISN_STOREV:
|
||||
case ISN_STRINDEX:
|
||||
case ISN_STRSLICE:
|
||||
case ISN_THROW:
|
||||
case ISN_TRY:
|
||||
// nothing allocated
|
||||
|
@@ -2297,6 +2297,32 @@ call_def_function(
|
||||
}
|
||||
break;
|
||||
|
||||
case ISN_ANYINDEX:
|
||||
case ISN_ANYSLICE:
|
||||
{
|
||||
int is_slice = iptr->isn_type == ISN_ANYSLICE;
|
||||
typval_T *var1, *var2;
|
||||
int res;
|
||||
|
||||
// index: composite is at stack-2, index at stack-1
|
||||
// slice: composite is at stack-3, indexes at stack-2 and
|
||||
// stack-1
|
||||
tv = is_slice ? STACK_TV_BOT(-3) : STACK_TV_BOT(-2);
|
||||
if (check_can_index(tv, TRUE, TRUE) == FAIL)
|
||||
goto on_error;
|
||||
var1 = is_slice ? STACK_TV_BOT(-2) : STACK_TV_BOT(-1);
|
||||
var2 = is_slice ? STACK_TV_BOT(-1) : NULL;
|
||||
res = eval_index_inner(tv, is_slice,
|
||||
var1, var2, NULL, -1, TRUE);
|
||||
clear_tv(var1);
|
||||
if (is_slice)
|
||||
clear_tv(var2);
|
||||
ectx.ec_stack.ga_len -= is_slice ? 2 : 1;
|
||||
if (res == FAIL)
|
||||
goto on_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case ISN_SLICE:
|
||||
{
|
||||
list_T *list;
|
||||
@@ -3133,6 +3159,8 @@ ex_disassemble(exarg_T *eap)
|
||||
case ISN_STRSLICE: smsg("%4d STRSLICE", 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;
|
||||
case ISN_ANYSLICE: smsg("%4d ANYSLICE", current); break;
|
||||
case ISN_SLICE: smsg("%4d SLICE %lld",
|
||||
current, iptr->isn_arg.number); break;
|
||||
case ISN_GETITEM: smsg("%4d ITEM %lld",
|
||||
|
Reference in New Issue
Block a user