diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/eval.c | 49 | ||||
| -rw-r--r-- | src/nvim/testdir/test_listdict.vim | 4 | 
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}  | 
