summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-04 19:12:14 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-04 19:12:14 +0100
commitc5e6a7179d7dee4315b412b56e172bb1ff092d3e (patch)
tree70eae554a7a7cb493df307f92b1f0372033132bf
parent6cd42db9dc1251b052b97d47bafc063eacac1b3e (diff)
downloadvim-git-8.2.2090.tar.gz
patch 8.2.2090: Vim9: dict does not accept a key in quotesv8.2.2090
Problem: Vim9: dict does not accept a key in quotes. Solution: Recognize a key in single or double quotes.
-rw-r--r--runtime/doc/vim9.txt22
-rw-r--r--src/dict.c54
-rw-r--r--src/proto/dict.pro1
-rw-r--r--src/testdir/test_vim9_expr.vim3
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c30
6 files changed, 83 insertions, 29 deletions
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt
index 085e4453e..5b0fded94 100644
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -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}
diff --git a/src/dict.c b/src/dict.c
index 819f5fa0b..311b0038d 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -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);
@@ -815,6 +815,47 @@ get_literal_key(char_u **arg, typval_T *tv)
}
/*
+ * 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 "{".
* "literal" is TRUE for #{key: val}
@@ -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
{
diff --git a/src/proto/dict.pro b/src/proto/dict.pro
index 0ba83657d..dbfdcdcbb 100644
--- a/src/proto/dict.pro
+++ b/src/proto/dict.pro
@@ -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);
diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim
index 4d0535130..a0593eadc 100644
--- a/src/testdir/test_vim9_expr.vim
+++ b/src/testdir/test_vim9_expr.vim
@@ -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)
diff --git a/src/version.c b/src/version.c
index 8b8a6c32a..2061ea0a3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2090,
+/**/
2089,
/**/
2088,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index 4b8a8ad71..2cd4b52c0 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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)