summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
5 files changed, 69 insertions, 21 deletions
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)