To: vim_dev@googlegroups.com Subject: Patch 8.2.1247 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1247 Problem: Vim9: cannot index a character in a string. Solution: Add ISN_STRINDEX instruction. (closes #6478) Files: src/vim9.h, src/vim9compile.c, src/vim9execute.c, src/testdir/test_vim9_expr.vim *** ../vim-8.2.1246/src/vim9.h 2020-07-09 21:20:41.912126818 +0200 --- src/vim9.h 2020-07-19 17:34:57.894654302 +0200 *************** *** 111,117 **** // expression operations ISN_CONCAT, ! ISN_INDEX, // [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] --- 111,118 ---- // expression operations ISN_CONCAT, ! 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] *** ../vim-8.2.1246/src/vim9compile.c 2020-07-19 17:16:58.686848586 +0200 --- src/vim9compile.c 2020-07-19 17:29:34.055768581 +0200 *************** *** 3752,3757 **** --- 3752,3758 ---- // 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,3809 **** if (generate_instr_drop(cctx, ISN_MEMBER, 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) return FAIL; } else --- 3800,3816 ---- 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_LISTINDEX, 1) == FAIL) return FAIL; } else *************** *** 7542,7548 **** case ISN_EXECCONCAT: case ISN_EXECUTE: case ISN_FOR: ! case ISN_INDEX: case ISN_GETITEM: case ISN_SLICE: case ISN_MEMBER: --- 7549,7556 ---- case ISN_EXECCONCAT: case ISN_EXECUTE: case ISN_FOR: ! case ISN_LISTINDEX: ! case ISN_STRINDEX: case ISN_GETITEM: case ISN_SLICE: case ISN_MEMBER: *** ../vim-8.2.1246/src/vim9execute.c 2020-07-19 14:03:05.063941901 +0200 --- src/vim9execute.c 2020-07-19 17:42:57.469802818 +0200 *************** *** 2122,2128 **** } break; ! case ISN_INDEX: { list_T *list; varnumber_T n; --- 2122,2165 ---- } break; ! 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,2953 **** // expression operations case ISN_CONCAT: smsg("%4d CONCAT", current); break; ! case ISN_INDEX: smsg("%4d INDEX", current); break; case ISN_SLICE: smsg("%4d SLICE %lld", current, iptr->isn_arg.number); break; case ISN_GETITEM: smsg("%4d ITEM %lld", --- 2984,2991 ---- // expression operations case ISN_CONCAT: smsg("%4d CONCAT", 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", *** ../vim-8.2.1246/src/testdir/test_vim9_expr.vim 2020-07-19 15:49:45.732131023 +0200 --- src/testdir/test_vim9_expr.vim 2020-07-19 17:54:58.083798335 +0200 *************** *** 1509,1514 **** --- 1509,1523 ---- 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) *** ../vim-8.2.1246/src/version.c 2020-07-19 17:16:58.686848586 +0200 --- src/version.c 2020-07-19 17:55:25.867713613 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1247, /**/ -- Everybody lies, but it doesn't matter since nobody listens. -- Lieberman's Law /// 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 ///