]> granicus.if.org Git - vim/commitdiff
patch 8.2.1247: Vim9: cannot index a character in a string v8.2.1247
authorBram Moolenaar <Bram@vim.org>
Sun, 19 Jul 2020 15:55:44 +0000 (17:55 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 19 Jul 2020 15:55:44 +0000 (17:55 +0200)
Problem:    Vim9: cannot index a character in a string.
Solution:   Add ISN_STRINDEX instruction. (closes #6478)

src/testdir/test_vim9_expr.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index a92254375bdfde64fa4453bdd1155fd278a491e5..de88ea7d8f30f2e62d314e72ae7d50cff1bd7d8d 100644 (file)
@@ -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)
index e1df00738fc0d91c63090aad152bbb98f7e16d5c..559d86499e2f8939465d4b505bf69440bb47002b 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1247,
 /**/
     1246,
 /**/
index 10f983ca976de33962986e1f1a0c2ea058e237e6..39d36f9735dca9757c2126b7193d28051190bc20 100644 (file)
@@ -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]
index 31cb31e011938433f8ad9d53b50e6544814549f7..a9db1d0b77489d5da8ebc1f23fbcb682e2b8d39c 100644 (file)
@@ -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:
index 7ba76e544c69dbe113f1dcb24b3e1a72986e9da8..9612bf461fd70d9cf1590ed6f70c29d3889011c3 100644 (file)
@@ -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",