]> granicus.if.org Git - vim/commitdiff
patch 8.2.2090: Vim9: dict does not accept a key in quotes v8.2.2090
authorBram Moolenaar <Bram@vim.org>
Fri, 4 Dec 2020 18:12:14 +0000 (19:12 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 4 Dec 2020 18:12:14 +0000 (19:12 +0100)
Problem:    Vim9: dict does not accept a key in quotes.
Solution:   Recognize a key in single or double quotes.

runtime/doc/vim9.txt
src/dict.c
src/proto/dict.pro
src/testdir/test_vim9_expr.vim
src/version.c
src/vim9compile.c

index 085e4453e0f2dc9b072b7cce1615f10e1a3206ee..5b0fded9448d6d2e1b82131d56ff2a87ae90926d 100644 (file)
@@ -1,4 +1,4 @@
-*vim9.txt*     For Vim version 8.2.  Last change: 2020 Nov 25
+*vim9.txt*     For Vim version 8.2.  Last change: 2020 Dec 04
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -436,19 +436,25 @@ Dictionary literals ~
 Traditionally Vim has supported dictionary literals with a {} syntax: >
        let dict = {'key': value}
 
-Later it became clear that using a simple key name is very common, thus
-literally dictionaries were introduced in a backwards compatible way: >
+Later it became clear that using a simple text key is very common, thus
+literal dictionaries were introduced in a backwards compatible way: >
        let dict = #{key: value}
 
-However, this #{} syntax is unlike any existing language.  As it appears that
-using a literal key is much more common than using an expression, and
+However, this #{} syntax is unlike any existing language.  As it turns out
+that using a literal key is much more common than using an expression, and
 considering that JavaScript uses this syntax, using the {} form for dictionary
-literals was considered a much more useful syntax.  In Vim9 script the {} form
+literals is considered a much more useful syntax.  In Vim9 script the {} form
 uses literal keys: >
        let dict = {key: value}
 
-In case an expression needs to be used for the key, square brackets can be
-used, just like in JavaScript: >
+This works for alphanumeric characters, underscore and dash.  If you want to
+use another character, use a single or double quoted string: >
+       let dict = {'key with space': value}
+       let dict = {"key\twith\ttabs": value}
+       let dict = {'': value}                  # empty key
+
+In case the key needs to be an expression, square brackets can be used, just
+like in JavaScript: >
        let dict = {["key" .. nr]: value}
 
 
index 819f5fa0ba41b675c25c9b72e27475281ae87e43..311b0038d1cf1ce495c8ebe1d0e649add8460b85 100644 (file)
@@ -801,7 +801,7 @@ skip_literal_key(char_u *key)
  * Return FAIL when there is no valid key.
  */
     static int
-get_literal_key(char_u **arg, typval_T *tv)
+get_literal_key_tv(char_u **arg, typval_T *tv)
 {
     char_u *p = skip_literal_key(*arg);
 
@@ -814,6 +814,47 @@ get_literal_key(char_u **arg, typval_T *tv)
     return OK;
 }
 
+/*
+ * Get a literal key for a Vim9 dict:
+ * {"name": value},
+ * {'name': value},
+ * {name: value} use "name" as a literal key
+ * Return the key in allocated memory or NULL in the case of an error.
+ * "arg" is advanced to just after the key.
+ */
+    char_u *
+get_literal_key(char_u **arg)
+{
+    char_u     *key;
+    char_u     *end;
+    typval_T   rettv;
+
+    if (**arg == '\'')
+    {
+       if (eval_lit_string(arg, &rettv, TRUE) == FAIL)
+           return NULL;
+       key = rettv.vval.v_string;
+    }
+    else if (**arg == '"')
+    {
+       if (eval_string(arg, &rettv, TRUE) == FAIL)
+           return NULL;
+       key = rettv.vval.v_string;
+    }
+    else
+    {
+       end = skip_literal_key(*arg);
+       if (end == *arg)
+       {
+           semsg(_(e_invalid_key_str), *arg);
+           return NULL;
+       }
+       key = vim_strnsave(*arg, end - *arg);
+       *arg = end;
+    }
+    return key;
+}
+
 /*
  * Allocate a variable for a Dictionary and fill it from "*arg".
  * "*arg" points to the "{".
@@ -864,10 +905,17 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
     {
        int     has_bracket = vim9script && **arg == '[';
 
-       if (literal || (vim9script && !has_bracket))
+       if (literal)
+       {
+           if (get_literal_key_tv(arg, &tvkey) == FAIL)
+               goto failret;
+       }
+       else if (vim9script && !has_bracket)
        {
-           if (get_literal_key(arg, &tvkey) == FAIL)
+           tvkey.vval.v_string = get_literal_key(arg);
+           if (tvkey.vval.v_string == NULL)
                goto failret;
+           tvkey.v_type = VAR_STRING;
        }
        else
        {
index 0ba83657d929a9776a418e3c031cbaa99e21a211..dbfdcdcbbd94f1eec3b6008b5acc65c858197889 100644 (file)
@@ -34,6 +34,7 @@ varnumber_T dict_get_number_check(dict_T *d, char_u *key);
 varnumber_T dict_get_bool(dict_T *d, char_u *key, int def);
 char_u *dict2string(typval_T *tv, int copyID, int restore_copyID);
 char_u *skip_literal_key(char_u *key);
+char_u *get_literal_key(char_u **arg);
 int eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal);
 void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
 dictitem_T *dict_lookup(hashitem_T *hi);
index 4d0535130daad83ecdc6f42424dfe1aa12d8f3f2..a0593eadc47e2942cd0326a896d7c37724571b73 100644 (file)
@@ -1930,12 +1930,13 @@ def Test_expr7_dict()
 
       assert_equal(g:test_space_dict, {['']: 'empty', [' ']: 'space'})
       assert_equal(g:test_hash_dict, {one: 1, two: 2})
+
+      assert_equal({['a a']: 1, ['b/c']: 2}, {'a a': 1, "b/c": 2})
   END
   CheckDefAndScriptSuccess(lines)
  
   # legacy syntax doesn't work
   CheckDefFailure(["var x = #{key: 8}"], 'E1097:', 2)
-  CheckDefFailure(["var x = {'key': 8}"], 'E1014:', 1)
   CheckDefFailure(["var x = 'a' .. #{a: 1}"], 'E1097:', 2)
 
   CheckDefFailure(["var x = {a:8}"], 'E1069:', 1)
index 8b8a6c32a76c51e9b8fcec04288558964e6b3508..2061ea0a3249c309b534741b5c735e1ae0a81bb6 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2090,
 /**/
     2089,
 /**/
index 4b8a8ad7177cdea1d52ea0ee8214113ddd7d8ecb..2cd4b52c0abfc4595432b4b0efa872c1411c4c41 100644 (file)
@@ -3024,26 +3024,11 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
        if (**arg == '}')
            break;
 
-       // {name: value} uses "name" as a literal key and
-       // {[expr]: value} uses an evaluated key.
-       if (**arg != '[')
-       {
-           char_u  *end = skip_literal_key(*arg);
-
-           if (end == *arg)
-           {
-               semsg(_(e_invalid_key_str), *arg);
-               return FAIL;
-           }
-           key = vim_strnsave(*arg, end - *arg);
-           if (generate_PUSHS(cctx, key) == FAIL)
-               return FAIL;
-           *arg = end;
-       }
-       else
+       if (**arg == '[')
        {
            isn_T       *isn;
 
+           // {[expr]: value} uses an evaluated key.
            *arg = skipwhite(*arg + 1);
            if (compile_expr0(arg, cctx) == FAIL)
                return FAIL;
@@ -3066,6 +3051,17 @@ compile_dict(char_u **arg, cctx_T *cctx, ppconst_T *ppconst)
            }
            ++*arg;
        }
+       else
+       {
+           // {"name": value},
+           // {'name': value},
+           // {name: value} use "name" as a literal key
+           key = get_literal_key(arg);
+           if (key == NULL)
+               return FAIL;
+           if (generate_PUSHS(cctx, key) == FAIL)
+               return FAIL;
+       }
 
        // Check for duplicate keys, if using string keys.
        if (key != NULL)