# HG changeset patch # User Bram Moolenaar # Date 1595174404 -7200 # Node ID 320581a133d943cba154f154310a4abe309a32f3 # Parent 6b34289ace89d3946393a7db98505becced9ea3c patch 8.2.1247: Vim9: cannot index a character in a string Commit: https://github.com/vim/vim/commit/bf9d8c3765a5255c0a0b577ca2e25d70a8bcb688 Author: Bram Moolenaar Date: Sun Jul 19 17:55:44 2020 +0200 patch 8.2.1247: Vim9: cannot index a character in a string Problem: Vim9: cannot index a character in a string. Solution: Add ISN_STRINDEX instruction. (closes https://github.com/vim/vim/issues/6478) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1509,6 +1509,15 @@ def Test_expr7_trailing() assert_equal(123, d.key) enddef +def Test_expr7_subscript() + let text = 'abcdef' + assert_equal('', text[-1]) + assert_equal('a', text[0]) + assert_equal('e', text[4]) + assert_equal('f', text[5]) + assert_equal('', text[6]) +enddef + def Test_expr7_subscript_linebreak() let range = range( 3) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1247, +/**/ 1246, /**/ 1245, diff --git a/src/vim9.h b/src/vim9.h --- a/src/vim9.h +++ b/src/vim9.h @@ -111,7 +111,8 @@ typedef enum { // expression operations ISN_CONCAT, - ISN_INDEX, // [expr] list index + ISN_STRINDEX, // [expr] string index + ISN_LISTINDEX, // [expr] list index 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] diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3752,6 +3752,7 @@ compile_subscript( // list index: list[123] // dict member: dict[key] + // string index: text[123] // TODO: blob index // TODO: more arguments // TODO: recognize list or dict at runtime @@ -3799,11 +3800,17 @@ compile_subscript( if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) return FAIL; } + else if (vtype == VAR_STRING) + { + *typep = &t_number; + if (generate_instr_drop(cctx, ISN_STRINDEX, 1) == FAIL) + return FAIL; + } else if (vtype == VAR_LIST || *typep == &t_any) { if ((*typep)->tt_type == VAR_LIST) *typep = (*typep)->tt_member; - if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL) + if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL) return FAIL; } else @@ -7542,7 +7549,8 @@ delete_instr(isn_T *isn) case ISN_EXECCONCAT: case ISN_EXECUTE: case ISN_FOR: - case ISN_INDEX: + case ISN_LISTINDEX: + case ISN_STRINDEX: case ISN_GETITEM: case ISN_SLICE: case ISN_MEMBER: diff --git a/src/vim9execute.c b/src/vim9execute.c --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2122,7 +2122,44 @@ call_def_function( } break; - case ISN_INDEX: + case ISN_STRINDEX: + { + char_u *s; + varnumber_T n; + char_u *res; + + // string index: string is at stack-2, index at stack-1 + tv = STACK_TV_BOT(-2); + if (tv->v_type != VAR_STRING) + { + emsg(_(e_stringreq)); + goto on_error; + } + s = tv->vval.v_string; + + tv = STACK_TV_BOT(-1); + if (tv->v_type != VAR_NUMBER) + { + emsg(_(e_number_exp)); + goto on_error; + } + n = tv->vval.v_number; + + // The resulting variable is a string of a single + // character. If the index is too big or negative the + // result is empty. + if (n < 0 || n >= (varnumber_T)STRLEN(s)) + res = NULL; + else + res = vim_strnsave(s + n, 1); + --ectx.ec_stack.ga_len; + tv = STACK_TV_BOT(-1); + vim_free(tv->vval.v_string); + tv->vval.v_string = res; + } + break; + + case ISN_LISTINDEX: { list_T *list; varnumber_T n; @@ -2947,7 +2984,8 @@ ex_disassemble(exarg_T *eap) // expression operations case ISN_CONCAT: smsg("%4d CONCAT", current); break; - case ISN_INDEX: smsg("%4d INDEX", current); break; + case ISN_STRINDEX: smsg("%4d STRINDEX", current); break; + case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break; case ISN_SLICE: smsg("%4d SLICE %lld", current, iptr->isn_arg.number); break; case ISN_GETITEM: smsg("%4d ITEM %lld",