summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-19 17:55:44 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-19 17:55:44 +0200
commitbf9d8c3765a5255c0a0b577ca2e25d70a8bcb688 (patch)
treed2f055157a14c8ddb1ff107379f04bba156f87b2
parentb209750b5e907003568c20856215122670ee22d2 (diff)
patch 8.2.1247: Vim9: cannot index a character in a stringv8.2.1247
Problem: Vim9: cannot index a character in a string. Solution: Add ISN_STRINDEX instruction. (closes #6478)
-rw-r--r--src/testdir/test_vim9_expr.vim9
-rw-r--r--src/version.c2
-rw-r--r--src/vim9.h3
-rw-r--r--src/vim9compile.c12
-rw-r--r--src/vim9execute.c42
5 files changed, 63 insertions, 5 deletions
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index a92254375b..de88ea7d8f 100644
--- 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
index e1df00738f..559d86499e 100644
--- 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
index 10f983ca97..39d36f9735 100644
--- 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
index 31cb31e011..a9db1d0b77 100644
--- 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
index 7ba76e544c..9612bf461f 100644
--- 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",