aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c49
-rw-r--r--src/nvim/testdir/test_listdict.vim4
2 files changed, 45 insertions, 8 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 24192dfefa..70549b950d 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -3905,6 +3905,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
// (expression) nested expression
// [expr, expr] List
// {key: val, key: val} Dictionary
+// *{key: val, key: val} Dictionary with literal keys
//
// Also handle:
// ! in front logical NOT
@@ -4012,11 +4013,21 @@ static int eval7(
case '[': ret = get_list_tv(arg, rettv, evaluate);
break;
+ // Dictionary: *{key: val, key: val}
+ case '*':
+ if ((*arg)[1] == '{') {
+ (*arg)++;
+ ret = dict_get_tv(arg, rettv, evaluate, true);
+ } else {
+ ret = NOTDONE;
+ }
+ break;
+
// Lambda: {arg, arg -> expr}
- // Dictionary: {key: val, key: val}
+ // Dictionary: {'key': val, 'key': val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = dict_get_tv(arg, rettv, evaluate);
+ ret = dict_get_tv(arg, rettv, evaluate, false);
}
break;
@@ -5347,11 +5358,31 @@ static inline bool set_ref_dict(dict_T *dict, int copyID)
return false;
}
-/*
- * Allocate a variable for a Dictionary and fill it from "*arg".
- * Return OK or FAIL. Returns NOTDONE for {expr}.
- */
-static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
+
+// Get the key for *{key: val} into "tv" and advance "arg".
+// Return FAIL when there is no valid key.
+static int get_literal_key(char_u **arg, typval_T *tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *p;
+
+ if (!ASCII_ISALNUM(**arg) && **arg != '_' && **arg != '-') {
+ return FAIL;
+ }
+ for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {
+ }
+ tv->v_type = VAR_STRING;
+ tv->vval.v_string = vim_strnsave(*arg, (int)(p - *arg));
+
+ *arg = skipwhite(p);
+ return OK;
+}
+
+// Allocate a variable for a Dictionary and fill it from "*arg".
+// "literal" is true for *{key: val}
+// Return OK or FAIL. Returns NOTDONE for {expr}.
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate,
+ bool literal)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -5385,7 +5416,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
*arg = skipwhite(*arg + 1);
while (**arg != '}' && **arg != NUL) {
- if (eval1(arg, &tvkey, evaluate) == FAIL) { // recursive!
+ if ((literal
+ ? get_literal_key(arg, &tvkey)
+ : eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive!
goto failret;
}
if (**arg != ':') {
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index bea62cb0ad..7b11885cc0 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -280,6 +280,10 @@ func Test_dict_func_remove_in_use()
call assert_equal(expected, d.func(string(remove(d, 'func'))))
endfunc
+func Test_dict_literal_keys()
+ call assert_equal({'one': 1, 'two2': 2, '3three': 3, '44': 4}, *{one: 1, two2: 2, 3three: 3, 44: 4},)
+endfunc
+
" Nasty: deepcopy() dict that refers to itself (fails when noref used)
func Test_dict_deepcopy()
let d = {1:1, 2:2}