To: vim_dev@googlegroups.com Subject: Patch 8.2.1466 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 #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", "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", "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 + 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 -- Bram@Moolenaar.net -- 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 ///