Patch 8.2.1466
Problem: Vim9: cannot index or slice a variable with type "any".
Solution: Add runtime index and slice.
Files: src/eval.c, src/proto/eval.pro, src/vim9compile.c,
src/vim9execute.c, src/vim9.h, src/errors.h, src/list.c,
src/testdir/test_vim9_expr.vim,
src/testdir/test_vim9_disassemble.vim,
src/testdir/test_vim9_script.vim
*** ../vim-8.2.1465/src/eval.c 2020-08-16 14:48:14.377965877 +0200
--- src/eval.c 2020-08-16 17:07:16.209603356 +0200
***************
*** 20,27 ****
# include <float.h>
#endif
- static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
-
#define NAMESPACE_CHAR (char_u *)"abglstvw"
/*
--- 20,25 ----
***************
*** 928,934 ****
if (lp->ll_tv->v_type == VAR_DICT)
{
if (!quiet)
! emsg(_(e_dictrange));
clear_tv(&var1);
return NULL;
}
--- 926,932 ----
if (lp->ll_tv->v_type == VAR_DICT)
{
if (!quiet)
! emsg(_(e_cannot_slice_dictionary));
clear_tv(&var1);
return NULL;
}
***************
*** 3549,3595 ****
&& (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;
! switch (rettv->v_type)
! {
! 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(_("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);
--- 3547,3558 ----
&& (evalarg->eval_flags & EVAL_EVALUATE);
int empty1 = FALSE, empty2 = FALSE;
typval_T var1, var2;
int range = FALSE;
char_u *key = NULL;
+ int keylen = -1;
! if (check_can_index(rettv, evaluate, verbose) == FAIL)
! return FAIL;
init_tv(&var1);
init_tv(&var2);
***************
*** 3599,3609 ****
* dict.name
*/
key = *arg + 1;
! for (len = 0; eval_isdictc(key[len]); ++len)
;
! if (len == 0)
return FAIL;
! *arg = skipwhite(key + len);
}
else
{
--- 3562,3572 ----
* dict.name
*/
key = *arg + 1;
! for (keylen = 0; eval_isdictc(key[keylen]); ++keylen)
;
! if (keylen == 0)
return FAIL;
! *arg = skipwhite(key + keylen);
}
else
{
***************
*** 3666,3714 ****
if (evaluate)
{
! n1 = 0;
! if (!empty1 && rettv->v_type != VAR_DICT)
! {
! n1 = tv_get_number(&var1);
clear_tv(&var1);
- }
if (range)
! {
! if (empty2)
! n2 = -1;
! else
{
! n2 = tv_get_number(&var2);
! clear_tv(&var2);
}
! }
! switch (rettv->v_type)
{
! case VAR_UNKNOWN:
! case VAR_ANY:
! case VAR_VOID:
! case VAR_FUNC:
! case VAR_PARTIAL:
! case VAR_FLOAT:
! case VAR_BOOL:
! case VAR_SPECIAL:
! case VAR_JOB:
! case VAR_CHANNEL:
! break; // not evaluating, skipping over subscript
- case VAR_NUMBER:
- case VAR_STRING:
- s = tv_get_string(rettv);
len = (long)STRLEN(s);
if (in_vim9script())
{
! if (range)
s = string_slice(s, n1, n2);
else
s = char_from_string(s, n1);
}
! else if (range)
{
// The resulting variable is a substring. If the indexes
// are out of range the result is empty.
--- 3629,3760 ----
if (evaluate)
{
! 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)
! {
! 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);
! }
!
! switch (rettv->v_type)
! {
! case VAR_UNKNOWN:
! case VAR_ANY:
! case VAR_VOID:
! case VAR_FUNC:
! case VAR_PARTIAL:
! case VAR_FLOAT:
! case VAR_BOOL:
! case VAR_SPECIAL:
! case VAR_JOB:
! case VAR_CHANNEL:
! break; // not evaluating, skipping over subscript
!
! case VAR_NUMBER:
! case VAR_STRING:
! {
! char_u *s = tv_get_string(rettv);
len = (long)STRLEN(s);
if (in_vim9script())
{
! if (is_range)
s = string_slice(s, n1, n2);
else
s = char_from_string(s, n1);
}
! else if (is_range)
{
// The resulting variable is a substring. If the indexes
// are out of range the result is empty.
***************
*** 3740,3858 ****
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)
{
! // 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 - 1;
! 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();
!
! 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);
}
! break;
!
! case VAR_LIST:
! if (empty1)
! n1 = 0;
! if (empty2)
! n2 = -1;
! if (list_slice_or_index(rettv->vval.v_list,
! 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;
! if (len == -1)
! {
! key = tv_get_string_chk(&var1);
! if (key == NULL)
! {
! clear_tv(&var1);
! return FAIL;
! }
! }
! item = dict_find(rettv->vval.v_dict, key, (int)len);
! 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);
- clear_tv(rettv);
- *rettv = var1;
}
- break;
- }
- }
return OK;
}
--- 3786,3892 ----
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 (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 - 1;
! 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);
! }
! break;
! case VAR_LIST:
! if (var1 == NULL)
! n1 = 0;
! if (var2 == NULL)
! n2 = -1;
! if (list_slice_or_index(rettv->vval.v_list,
! is_range, n1, n2, rettv, verbose) == FAIL)
! return FAIL;
! break;
! case VAR_DICT:
! {
! dictitem_T *item;
! typval_T tmp;
! if (key == NULL)
! {
! key = tv_get_string_chk(var1);
! if (key == NULL)
return FAIL;
}
+ item = dict_find(rettv->vval.v_dict, key, (int)keylen);
+
+ if (item == NULL && verbose)
+ semsg(_(e_dictkey), key);
+ if (item == NULL)
+ return FAIL;
+
+ copy_tv(&item->di_tv, &tmp);
+ clear_tv(rettv);
+ *rettv = tmp;
+ }
+ break;
+ }
return OK;
}
***************
*** 5292,5300 ****
* "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.
*/
! static size_t
char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
{
varnumber_T nchar = idx;
--- 5326,5334 ----
* "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 -1.
*/
! static long
char_idx2byte(char_u *str, size_t str_len, varnumber_T idx)
{
varnumber_T nchar = idx;
***************
*** 5317,5324 ****
nbyte -= mb_head_off(str, str + nbyte);
++nchar;
}
}
! return nbyte;
}
/*
--- 5351,5360 ----
nbyte -= mb_head_off(str, str + nbyte);
++nchar;
}
+ if (nchar < 0)
+ return -1;
}
! return (long)nbyte;
}
/*
***************
*** 5328,5351 ****
char_u *
string_slice(char_u *str, varnumber_T first, varnumber_T last)
{
! size_t start_byte, end_byte;
! size_t slen;
if (str == NULL)
return NULL;
slen = STRLEN(str);
start_byte = char_idx2byte(str, slen, first);
if (last == -1)
end_byte = slen;
else
{
end_byte = char_idx2byte(str, slen, last);
! if (end_byte < slen)
// end index is inclusive
end_byte += MB_CPTR2LEN(str + end_byte);
}
! if (start_byte >= slen || end_byte <= start_byte)
return NULL;
return vim_strnsave(str + start_byte, end_byte - start_byte);
}
--- 5364,5389 ----
char_u *
string_slice(char_u *str, varnumber_T first, varnumber_T last)
{
! 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 >= 0 && end_byte < (long)slen)
// end index is inclusive
end_byte += MB_CPTR2LEN(str + end_byte);
}
! if (start_byte >= (long)slen || end_byte <= start_byte)
return NULL;
return vim_strnsave(str + start_byte, end_byte - start_byte);
}
*** ../vim-8.2.1465/src/proto/eval.pro 2020-08-15 21:09:03.281675788 +0200
--- src/proto/eval.pro 2020-08-16 15:48:47.286790791 +0200
***************
*** 37,42 ****
--- 37,44 ----
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);
*** ../vim-8.2.1465/src/vim9compile.c 2020-08-16 14:48:14.377965877 +0200
--- src/vim9compile.c 2020-08-16 15:42:15.249579900 +0200
***************
*** 3179,3198 ****
}
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)
return FAIL;
}
else
{
if ((*typep)->tt_type == VAR_LIST)
*typep = (*typep)->tt_member;
! if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
return FAIL;
}
}
--- 3179,3198 ----
}
else if (vtype == VAR_LIST || *typep == &t_any)
{
if (is_slice)
{
! 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,
! vtype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX,
! 1) == FAIL)
return FAIL;
}
}
***************
*** 7085,7095 ****
case ISN_2STRING_ANY:
case ISN_ADDBLOB:
case ISN_ADDLIST:
case ISN_BCALL:
case ISN_CATCH:
case ISN_CHECKNR:
case ISN_CHECKTYPE:
- case ISN_CHECKLEN:
case ISN_COMPAREANY:
case ISN_COMPAREBLOB:
case ISN_COMPAREBOOL:
--- 7085,7097 ----
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_COMPAREANY:
case ISN_COMPAREBLOB:
case ISN_COMPAREBOOL:
***************
*** 7102,7108 ****
case ISN_COMPARESTRING:
case ISN_CONCAT:
case ISN_DCALL:
- case ISN_SHUFFLE:
case ISN_DROP:
case ISN_ECHO:
case ISN_ECHOERR:
--- 7104,7109 ----
***************
*** 7111,7124 ****
case ISN_EXECCONCAT:
case ISN_EXECUTE:
case ISN_FOR:
- 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:
--- 7112,7121 ----
case ISN_EXECCONCAT:
case ISN_EXECUTE:
case ISN_FOR:
case ISN_GETITEM:
case ISN_JUMP:
+ case ISN_LISTINDEX:
+ case ISN_LISTSLICE:
case ISN_LOAD:
case ISN_LOADBDICT:
case ISN_LOADGDICT:
***************
*** 7128,7154 ****
case ISN_LOADTDICT:
case ISN_LOADV:
case ISN_LOADWDICT:
case ISN_NEGATENR:
case ISN_NEWDICT:
case ISN_NEWLIST:
- case ISN_OPNR:
- case ISN_OPFLOAT:
case ISN_OPANY:
case ISN_PCALL:
case ISN_PCALL_END:
case ISN_PUSHF:
case ISN_PUSHNR:
- case ISN_PUSHBOOL:
case ISN_PUSHSPEC:
case ISN_RETURN:
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_THROW:
case ISN_TRY:
// nothing allocated
--- 7125,7156 ----
case ISN_LOADTDICT:
case ISN_LOADV:
case ISN_LOADWDICT:
+ case ISN_MEMBER:
case ISN_NEGATENR:
case ISN_NEWDICT:
case ISN_NEWLIST:
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_PUSHSPEC:
case ISN_RETURN:
+ case ISN_SHUFFLE:
+ case ISN_SLICE:
case ISN_STORE:
! 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
*** ../vim-8.2.1465/src/vim9execute.c 2020-08-16 14:48:14.377965877 +0200
--- src/vim9execute.c 2020-08-16 16:04:41.218107159 +0200
***************
*** 2297,2302 ****
--- 2297,2328 ----
}
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,3138 ****
--- 3159,3166 ----
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",
*** ../vim-8.2.1465/src/vim9.h 2020-08-15 22:14:49.051890442 +0200
--- src/vim9.h 2020-08-16 15:39:00.006999100 +0200
***************
*** 120,125 ****
--- 120,127 ----
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]
*** ../vim-8.2.1465/src/errors.h 2020-08-16 14:48:14.377965877 +0200
--- src/errors.h 2020-08-16 17:11:34.235680579 +0200
***************
*** 21,26 ****
--- 21,30 ----
#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,77 ****
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
EXTERN char e_using_rcurly_outside_if_block_scope[]
INIT(= N_("E1025: using } outside of a block scope"));
EXTERN char e_missing_rcurly[]
--- 73,81 ----
INIT(= N_("E1021: const requires a value"));
EXTERN char e_type_or_initialization_required[]
INIT(= N_("E1022: type or initialization required"));
! // 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,152 ****
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_type_mismatch_for_v_variable[]
INIT(= N_("E1063: type mismatch for v: variable"));
// E1064 unused
--- 150,157 ----
INIT(= N_("E1060: expected dot after name: %s"));
EXTERN char e_cannot_find_function_str[]
INIT(= N_("E1061: Cannot find function %s"));
! 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
*** ../vim-8.2.1465/src/list.c 2020-08-16 14:48:14.377965877 +0200
--- src/list.c 2020-08-16 16:57:40.625890389 +0200
***************
*** 914,920 ****
semsg(_(e_listidx), n1);
return FAIL;
}
! n1 = len;
}
if (range)
{
--- 914,920 ----
semsg(_(e_listidx), n1);
return FAIL;
}
! n1 = n1 < 0 ? 0 : len;
}
if (range)
{
*** ../vim-8.2.1465/src/testdir/test_vim9_expr.vim 2020-08-16
14:48:14.377965877 +0200
--- src/testdir/test_vim9_expr.vim 2020-08-16 17:13:50.022669179 +0200
***************
*** 1457,1463 ****
4]
call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
! call CheckDefExecFailure(["let x = g:anint[3]"], 'E1029:')
call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
--- 1457,1463 ----
4]
call CheckDefFailure(["let x = 1234[3]"], 'E1107:')
! call CheckDefExecFailure(["let x = g:anint[3]"], 'E1062:')
call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:')
***************
*** 1768,1776 ****
call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"],
'E1029: Expected dict but got list')
enddef
! def Test_expr_index()
! # getting the one member should clear the list only after getting the item
! assert_equal('bbb', ['aaa', 'bbb', 'ccc'][1])
enddef
def Test_expr_member_vim9script()
--- 1768,1858 ----
call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"],
'E1029: Expected dict but got list')
enddef
! 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()
*** ../vim-8.2.1465/src/testdir/test_vim9_disassemble.vim 2020-08-15
22:14:49.055890417 +0200
--- src/testdir/test_vim9_disassemble.vim 2020-08-16 17:31:10.234924598
+0200
***************
*** 1091,1096 ****
--- 1091,1140 ----
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
*** ../vim-8.2.1465/src/testdir/test_vim9_script.vim 2020-08-16
14:48:14.377965877 +0200
--- src/testdir/test_vim9_script.vim 2020-08-16 17:19:57.395933434 +0200
***************
*** 793,800 ****
endtry
assert_equal(99, n)
- # TODO: this will change when index on "any" works
try
n = g:astring[3]
catch /E1029:/
n = 77
--- 793,800 ----
endtry
assert_equal(99, n)
try
+ # string slice returns a string, not a number
n = g:astring[3]
catch /E1029:/
n = 77
*** ../vim-8.2.1465/src/version.c 2020-08-16 14:48:14.377965877 +0200
--- src/version.c 2020-08-16 15:23:40.374474610 +0200
***************
*** 756,757 ****
--- 756,759 ----
{ /* Add new patch number below this line */
+ /**/
+ 1466,
/**/
--
hundred-and-one symptoms of being an internet addict:
217. Your sex life has drastically improved...so what if it's only cyber-sex!
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202008161533.07GFXxqx600579%40masaka.moolenaar.net.