1
0
forked from aniani/vim

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 #6478)
This commit is contained in:
Bram Moolenaar
2020-07-19 17:55:44 +02:00
parent b209750b5e
commit bf9d8c3765
5 changed files with 63 additions and 5 deletions

View File

@@ -1509,6 +1509,15 @@ def Test_expr7_trailing()
assert_equal(123, d.key) assert_equal(123, d.key)
enddef 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() def Test_expr7_subscript_linebreak()
let range = range( let range = range(
3) 3)

View File

@@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1247,
/**/ /**/
1246, 1246,
/**/ /**/

View File

@@ -111,7 +111,8 @@ typedef enum {
// expression operations // expression operations
ISN_CONCAT, 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_SLICE, // drop isn_arg.number items from start of list
ISN_GETITEM, // push list item, isn_arg.number is the index ISN_GETITEM, // push list item, isn_arg.number is the index
ISN_MEMBER, // dict[member] ISN_MEMBER, // dict[member]

View File

@@ -3752,6 +3752,7 @@ compile_subscript(
// list index: list[123] // list index: list[123]
// dict member: dict[key] // dict member: dict[key]
// string index: text[123]
// TODO: blob index // TODO: blob index
// TODO: more arguments // TODO: more arguments
// TODO: recognize list or dict at runtime // TODO: recognize list or dict at runtime
@@ -3799,11 +3800,17 @@ compile_subscript(
if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
return 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) else if (vtype == VAR_LIST || *typep == &t_any)
{ {
if ((*typep)->tt_type == VAR_LIST) if ((*typep)->tt_type == VAR_LIST)
*typep = (*typep)->tt_member; *typep = (*typep)->tt_member;
if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL) if (generate_instr_drop(cctx, ISN_LISTINDEX, 1) == FAIL)
return FAIL; return FAIL;
} }
else else
@@ -7542,7 +7549,8 @@ delete_instr(isn_T *isn)
case ISN_EXECCONCAT: case ISN_EXECCONCAT:
case ISN_EXECUTE: case ISN_EXECUTE:
case ISN_FOR: case ISN_FOR:
case ISN_INDEX: case ISN_LISTINDEX:
case ISN_STRINDEX:
case ISN_GETITEM: case ISN_GETITEM:
case ISN_SLICE: case ISN_SLICE:
case ISN_MEMBER: case ISN_MEMBER:

View File

@@ -2122,7 +2122,44 @@ call_def_function(
} }
break; 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; list_T *list;
varnumber_T n; varnumber_T n;
@@ -2947,7 +2984,8 @@ ex_disassemble(exarg_T *eap)
// expression operations // expression operations
case ISN_CONCAT: smsg("%4d CONCAT", current); break; 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", case ISN_SLICE: smsg("%4d SLICE %lld",
current, iptr->isn_arg.number); break; current, iptr->isn_arg.number); break;
case ISN_GETITEM: smsg("%4d ITEM %lld", case ISN_GETITEM: smsg("%4d ITEM %lld",