comparison src/eval.c @ 17922:4d63d47d87ef v8.1.1957

patch 8.1.1957: more code can be moved to evalvars.c Commit: https://github.com/vim/vim/commit/da6c03342117fb7f4a8110bd9e8627b612a05a64 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Sep 1 16:01:30 2019 +0200 patch 8.1.1957: more code can be moved to evalvars.c Problem: More code can be moved to evalvars.c. Solution: Move code to where it fits better. (Yegappan Lakshmanan, closes #4883)
author Bram Moolenaar <Bram@vim.org>
date Sun, 01 Sep 2019 16:15:03 +0200
parents e4d3b6c466d4
children 7f3283683d97
comparison
equal deleted inserted replaced
17921:14be395d672c 17922:4d63d47d87ef
35 * The last bit is used for previous_funccal, ignored when comparing. 35 * The last bit is used for previous_funccal, ignored when comparing.
36 */ 36 */
37 static int current_copyID = 0; 37 static int current_copyID = 0;
38 38
39 static int echo_attr = 0; /* attributes used for ":echo" */ 39 static int echo_attr = 0; /* attributes used for ":echo" */
40
41 /* The names of packages that once were loaded are remembered. */
42 static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
43 40
44 /* 41 /*
45 * Info used by a ":for" loop. 42 * Info used by a ":for" loop.
46 */ 43 */
47 typedef struct 44 typedef struct
154 evalvars_clear(); 151 evalvars_clear();
155 152
156 free_scriptnames(); 153 free_scriptnames();
157 free_locales(); 154 free_locales();
158 155
159 /* autoloaded script names */ 156 // autoloaded script names
160 ga_clear_strings(&ga_loaded); 157 free_autoload_scriptnames();
161 158
162 // unreferenced lists and dicts 159 // unreferenced lists and dicts
163 (void)garbage_collect(FALSE); 160 (void)garbage_collect(FALSE);
164 161
165 // functions not garbage collected 162 // functions not garbage collected
166 free_all_functions(); 163 free_all_functions();
167 } 164 }
168 #endif 165 #endif
169
170 static lval_T *redir_lval = NULL;
171 #define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
172 static garray_T redir_ga; /* only valid when redir_lval is not NULL */
173 static char_u *redir_endp = NULL;
174 static char_u *redir_varname = NULL;
175
176 /*
177 * Start recording command output to a variable
178 * When "append" is TRUE append to an existing variable.
179 * Returns OK if successfully completed the setup. FAIL otherwise.
180 */
181 int
182 var_redir_start(char_u *name, int append)
183 {
184 int save_emsg;
185 int err;
186 typval_T tv;
187
188 /* Catch a bad name early. */
189 if (!eval_isnamec1(*name))
190 {
191 emsg(_(e_invarg));
192 return FAIL;
193 }
194
195 /* Make a copy of the name, it is used in redir_lval until redir ends. */
196 redir_varname = vim_strsave(name);
197 if (redir_varname == NULL)
198 return FAIL;
199
200 redir_lval = ALLOC_CLEAR_ONE(lval_T);
201 if (redir_lval == NULL)
202 {
203 var_redir_stop();
204 return FAIL;
205 }
206
207 /* The output is stored in growarray "redir_ga" until redirection ends. */
208 ga_init2(&redir_ga, (int)sizeof(char), 500);
209
210 /* Parse the variable name (can be a dict or list entry). */
211 redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
212 FNE_CHECK_START);
213 if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL)
214 {
215 clear_lval(redir_lval);
216 if (redir_endp != NULL && *redir_endp != NUL)
217 /* Trailing characters are present after the variable name */
218 emsg(_(e_trailing));
219 else
220 emsg(_(e_invarg));
221 redir_endp = NULL; /* don't store a value, only cleanup */
222 var_redir_stop();
223 return FAIL;
224 }
225
226 /* check if we can write to the variable: set it to or append an empty
227 * string */
228 save_emsg = did_emsg;
229 did_emsg = FALSE;
230 tv.v_type = VAR_STRING;
231 tv.vval.v_string = (char_u *)"";
232 if (append)
233 set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)".");
234 else
235 set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
236 clear_lval(redir_lval);
237 err = did_emsg;
238 did_emsg |= save_emsg;
239 if (err)
240 {
241 redir_endp = NULL; /* don't store a value, only cleanup */
242 var_redir_stop();
243 return FAIL;
244 }
245
246 return OK;
247 }
248
249 /*
250 * Append "value[value_len]" to the variable set by var_redir_start().
251 * The actual appending is postponed until redirection ends, because the value
252 * appended may in fact be the string we write to, changing it may cause freed
253 * memory to be used:
254 * :redir => foo
255 * :let foo
256 * :redir END
257 */
258 void
259 var_redir_str(char_u *value, int value_len)
260 {
261 int len;
262
263 if (redir_lval == NULL)
264 return;
265
266 if (value_len == -1)
267 len = (int)STRLEN(value); /* Append the entire string */
268 else
269 len = value_len; /* Append only "value_len" characters */
270
271 if (ga_grow(&redir_ga, len) == OK)
272 {
273 mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
274 redir_ga.ga_len += len;
275 }
276 else
277 var_redir_stop();
278 }
279
280 /*
281 * Stop redirecting command output to a variable.
282 * Frees the allocated memory.
283 */
284 void
285 var_redir_stop(void)
286 {
287 typval_T tv;
288
289 if (EVALCMD_BUSY)
290 {
291 redir_lval = NULL;
292 return;
293 }
294
295 if (redir_lval != NULL)
296 {
297 /* If there was no error: assign the text to the variable. */
298 if (redir_endp != NULL)
299 {
300 ga_append(&redir_ga, NUL); /* Append the trailing NUL. */
301 tv.v_type = VAR_STRING;
302 tv.vval.v_string = redir_ga.ga_data;
303 /* Call get_lval() again, if it's inside a Dict or List it may
304 * have changed. */
305 redir_endp = get_lval(redir_varname, NULL, redir_lval,
306 FALSE, FALSE, 0, FNE_CHECK_START);
307 if (redir_endp != NULL && redir_lval->ll_name != NULL)
308 set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE,
309 (char_u *)".");
310 clear_lval(redir_lval);
311 }
312
313 /* free the collected output */
314 VIM_CLEAR(redir_ga.ga_data);
315
316 VIM_CLEAR(redir_lval);
317 }
318 VIM_CLEAR(redir_varname);
319 }
320
321 int
322 eval_charconvert(
323 char_u *enc_from,
324 char_u *enc_to,
325 char_u *fname_from,
326 char_u *fname_to)
327 {
328 int err = FALSE;
329
330 set_vim_var_string(VV_CC_FROM, enc_from, -1);
331 set_vim_var_string(VV_CC_TO, enc_to, -1);
332 set_vim_var_string(VV_FNAME_IN, fname_from, -1);
333 set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
334 if (eval_to_bool(p_ccv, &err, NULL, FALSE))
335 err = TRUE;
336 set_vim_var_string(VV_CC_FROM, NULL, -1);
337 set_vim_var_string(VV_CC_TO, NULL, -1);
338 set_vim_var_string(VV_FNAME_IN, NULL, -1);
339 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
340
341 if (err)
342 return FAIL;
343 return OK;
344 }
345
346 # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
347 int
348 eval_printexpr(char_u *fname, char_u *args)
349 {
350 int err = FALSE;
351
352 set_vim_var_string(VV_FNAME_IN, fname, -1);
353 set_vim_var_string(VV_CMDARG, args, -1);
354 if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
355 err = TRUE;
356 set_vim_var_string(VV_FNAME_IN, NULL, -1);
357 set_vim_var_string(VV_CMDARG, NULL, -1);
358
359 if (err)
360 {
361 mch_remove(fname);
362 return FAIL;
363 }
364 return OK;
365 }
366 # endif
367
368 # if defined(FEAT_DIFF) || defined(PROTO)
369 void
370 eval_diff(
371 char_u *origfile,
372 char_u *newfile,
373 char_u *outfile)
374 {
375 int err = FALSE;
376
377 set_vim_var_string(VV_FNAME_IN, origfile, -1);
378 set_vim_var_string(VV_FNAME_NEW, newfile, -1);
379 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
380 (void)eval_to_bool(p_dex, &err, NULL, FALSE);
381 set_vim_var_string(VV_FNAME_IN, NULL, -1);
382 set_vim_var_string(VV_FNAME_NEW, NULL, -1);
383 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
384 }
385
386 void
387 eval_patch(
388 char_u *origfile,
389 char_u *difffile,
390 char_u *outfile)
391 {
392 int err;
393
394 set_vim_var_string(VV_FNAME_IN, origfile, -1);
395 set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
396 set_vim_var_string(VV_FNAME_OUT, outfile, -1);
397 (void)eval_to_bool(p_pex, &err, NULL, FALSE);
398 set_vim_var_string(VV_FNAME_IN, NULL, -1);
399 set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
400 set_vim_var_string(VV_FNAME_OUT, NULL, -1);
401 }
402 # endif
403 166
404 /* 167 /*
405 * Top level evaluation function, returning a boolean. 168 * Top level evaluation function, returning a boolean.
406 * Sets "error" to TRUE if there was an error. 169 * Sets "error" to TRUE if there was an error.
407 * Return TRUE or FALSE. 170 * Return TRUE or FALSE.
668 } 431 }
669 --emsg_off; 432 --emsg_off;
670 433
671 return retval; 434 return retval;
672 } 435 }
673
674 #if defined(FEAT_SPELL) || defined(PROTO)
675 /*
676 * Evaluate an expression to a list with suggestions.
677 * For the "expr:" part of 'spellsuggest'.
678 * Returns NULL when there is an error.
679 */
680 list_T *
681 eval_spell_expr(char_u *badword, char_u *expr)
682 {
683 typval_T save_val;
684 typval_T rettv;
685 list_T *list = NULL;
686 char_u *p = skipwhite(expr);
687
688 /* Set "v:val" to the bad word. */
689 prepare_vimvar(VV_VAL, &save_val);
690 set_vim_var_string(VV_VAL, badword, -1);
691 if (p_verbose == 0)
692 ++emsg_off;
693
694 if (eval1(&p, &rettv, TRUE) == OK)
695 {
696 if (rettv.v_type != VAR_LIST)
697 clear_tv(&rettv);
698 else
699 list = rettv.vval.v_list;
700 }
701
702 if (p_verbose == 0)
703 --emsg_off;
704 clear_tv(get_vim_var_tv(VV_VAL));
705 restore_vimvar(VV_VAL, &save_val);
706
707 return list;
708 }
709
710 /*
711 * "list" is supposed to contain two items: a word and a number. Return the
712 * word in "pp" and the number as the return value.
713 * Return -1 if anything isn't right.
714 * Used to get the good word and score from the eval_spell_expr() result.
715 */
716 int
717 get_spellword(list_T *list, char_u **pp)
718 {
719 listitem_T *li;
720
721 li = list->lv_first;
722 if (li == NULL)
723 return -1;
724 *pp = tv_get_string(&li->li_tv);
725
726 li = li->li_next;
727 if (li == NULL)
728 return -1;
729 return (int)tv_get_number(&li->li_tv);
730 }
731 #endif
732 436
733 /* 437 /*
734 * Top level evaluation function. 438 * Top level evaluation function.
735 * Returns an allocated typval_T with the result. 439 * Returns an allocated typval_T with the result.
736 * Returns NULL when there is an error. 440 * Returns NULL when there is an error.
1151 } 855 }
1152 856
1153 if (lp->ll_di == NULL) 857 if (lp->ll_di == NULL)
1154 { 858 {
1155 // Can't add "v:" or "a:" variable. 859 // Can't add "v:" or "a:" variable.
1156 if (lp->ll_dict == &vimvardict 860 if (lp->ll_dict == get_vimvar_dict()
1157 || &lp->ll_dict->dv_hashtab == get_funccal_args_ht()) 861 || &lp->ll_dict->dv_hashtab == get_funccal_args_ht())
1158 { 862 {
1159 semsg(_(e_illvar), name); 863 semsg(_(e_illvar), name);
1160 clear_tv(&var1); 864 clear_tv(&var1);
1161 return NULL; 865 return NULL;
1918 while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) 1622 while ((c = *++arg) != NUL && (c == ' ' || c == '\t'))
1919 /* skip */ ; 1623 /* skip */ ;
1920 } 1624 }
1921 xp->xp_pattern = arg; 1625 xp->xp_pattern = arg;
1922 } 1626 }
1923
1924 #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
1925 /*
1926 * Delete all "menutrans_" variables.
1927 */
1928 void
1929 del_menutrans_vars(void)
1930 {
1931 hashitem_T *hi;
1932 int todo;
1933
1934 hash_lock(&globvarht);
1935 todo = (int)globvarht.ht_used;
1936 for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
1937 {
1938 if (!HASHITEM_EMPTY(hi))
1939 {
1940 --todo;
1941 if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
1942 delete_var(&globvarht, hi);
1943 }
1944 }
1945 hash_unlock(&globvarht);
1946 }
1947 #endif
1948 1627
1949 /* 1628 /*
1950 * Return TRUE if "pat" matches "text". 1629 * Return TRUE if "pat" matches "text".
1951 * Does not use 'cpo' and always uses 'magic'. 1630 * Does not use 'cpo' and always uses 'magic'.
1952 */ 1631 */
4213 /* tabpage-local variables */ 3892 /* tabpage-local variables */
4214 FOR_ALL_TABPAGES(tp) 3893 FOR_ALL_TABPAGES(tp)
4215 abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID, 3894 abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
4216 NULL, NULL); 3895 NULL, NULL);
4217 /* global variables */ 3896 /* global variables */
4218 abort = abort || set_ref_in_ht(&globvarht, copyID, NULL); 3897 abort = abort || garbage_collect_globvars(copyID);
4219 3898
4220 /* function-local variables */ 3899 /* function-local variables */
4221 abort = abort || set_ref_in_call_stack(copyID); 3900 abort = abort || set_ref_in_call_stack(copyID);
4222 3901
4223 /* named functions (matters for closures) */ 3902 /* named functions (matters for closures) */
4626 } 4305 }
4627 } 4306 }
4628 } 4307 }
4629 #endif 4308 #endif
4630 return abort; 4309 return abort;
4631 }
4632
4633 static char *
4634 get_var_special_name(int nr)
4635 {
4636 switch (nr)
4637 {
4638 case VVAL_FALSE: return "v:false";
4639 case VVAL_TRUE: return "v:true";
4640 case VVAL_NONE: return "v:none";
4641 case VVAL_NULL: return "v:null";
4642 }
4643 internal_error("get_var_special_name()");
4644 return "42";
4645 } 4310 }
4646 4311
4647 /* 4312 /*
4648 * Return a string with the string representation of a variable. 4313 * Return a string with the string representation of a variable.
4649 * If the memory is allocated "tofree" is set to it, otherwise NULL. 4314 * If the memory is allocated "tofree" is set to it, otherwise NULL.
6202 --recurse; 5867 --recurse;
6203 return ret; 5868 return ret;
6204 } 5869 }
6205 5870
6206 /* 5871 /*
6207 * This function is used by f_input() and f_inputdialog() functions. The third
6208 * argument to f_input() specifies the type of completion to use at the
6209 * prompt. The third argument to f_inputdialog() specifies the value to return
6210 * when the user cancels the prompt.
6211 */
6212 void
6213 get_user_input(
6214 typval_T *argvars,
6215 typval_T *rettv,
6216 int inputdialog,
6217 int secret)
6218 {
6219 char_u *prompt = tv_get_string_chk(&argvars[0]);
6220 char_u *p = NULL;
6221 int c;
6222 char_u buf[NUMBUFLEN];
6223 int cmd_silent_save = cmd_silent;
6224 char_u *defstr = (char_u *)"";
6225 int xp_type = EXPAND_NOTHING;
6226 char_u *xp_arg = NULL;
6227
6228 rettv->v_type = VAR_STRING;
6229 rettv->vval.v_string = NULL;
6230
6231 #ifdef NO_CONSOLE_INPUT
6232 /* While starting up, there is no place to enter text. When running tests
6233 * with --not-a-term we assume feedkeys() will be used. */
6234 if (no_console_input() && !is_not_a_term())
6235 return;
6236 #endif
6237
6238 cmd_silent = FALSE; /* Want to see the prompt. */
6239 if (prompt != NULL)
6240 {
6241 /* Only the part of the message after the last NL is considered as
6242 * prompt for the command line */
6243 p = vim_strrchr(prompt, '\n');
6244 if (p == NULL)
6245 p = prompt;
6246 else
6247 {
6248 ++p;
6249 c = *p;
6250 *p = NUL;
6251 msg_start();
6252 msg_clr_eos();
6253 msg_puts_attr((char *)prompt, echo_attr);
6254 msg_didout = FALSE;
6255 msg_starthere();
6256 *p = c;
6257 }
6258 cmdline_row = msg_row;
6259
6260 if (argvars[1].v_type != VAR_UNKNOWN)
6261 {
6262 defstr = tv_get_string_buf_chk(&argvars[1], buf);
6263 if (defstr != NULL)
6264 stuffReadbuffSpec(defstr);
6265
6266 if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
6267 {
6268 char_u *xp_name;
6269 int xp_namelen;
6270 long argt;
6271
6272 /* input() with a third argument: completion */
6273 rettv->vval.v_string = NULL;
6274
6275 xp_name = tv_get_string_buf_chk(&argvars[2], buf);
6276 if (xp_name == NULL)
6277 return;
6278
6279 xp_namelen = (int)STRLEN(xp_name);
6280
6281 if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
6282 &xp_arg) == FAIL)
6283 return;
6284 }
6285 }
6286
6287 if (defstr != NULL)
6288 {
6289 int save_ex_normal_busy = ex_normal_busy;
6290
6291 ex_normal_busy = 0;
6292 rettv->vval.v_string =
6293 getcmdline_prompt(secret ? NUL : '@', p, echo_attr,
6294 xp_type, xp_arg);
6295 ex_normal_busy = save_ex_normal_busy;
6296 }
6297 if (inputdialog && rettv->vval.v_string == NULL
6298 && argvars[1].v_type != VAR_UNKNOWN
6299 && argvars[2].v_type != VAR_UNKNOWN)
6300 rettv->vval.v_string = vim_strsave(tv_get_string_buf(
6301 &argvars[2], buf));
6302
6303 vim_free(xp_arg);
6304
6305 /* since the user typed this, no need to wait for return */
6306 need_wait_return = FALSE;
6307 msg_didout = FALSE;
6308 }
6309 cmd_silent = cmd_silent_save;
6310 }
6311
6312 /*
6313 * ":echo expr1 ..." print each argument separated with a space, add a 5872 * ":echo expr1 ..." print each argument separated with a space, add a
6314 * newline at the end. 5873 * newline at the end.
6315 * ":echon expr1 ..." print each argument plain. 5874 * ":echon expr1 ..." print each argument plain.
6316 */ 5875 */
6317 void 5876 void
6423 { 5982 {
6424 echo_attr = syn_name2attr(eap->arg); 5983 echo_attr = syn_name2attr(eap->arg);
6425 } 5984 }
6426 5985
6427 /* 5986 /*
5987 * Returns the :echo attribute
5988 */
5989 int
5990 get_echo_attr(void)
5991 {
5992 return echo_attr;
5993 }
5994
5995 /*
6428 * ":execute expr1 ..." execute the result of an expression. 5996 * ":execute expr1 ..." execute the result of an expression.
6429 * ":echomsg expr1 ..." Print a message 5997 * ":echomsg expr1 ..." Print a message
6430 * ":echoerr expr1 ..." Print an error 5998 * ":echoerr expr1 ..." Print an error
6431 * Each gets spaces around each argument and a newline at the end for 5999 * Each gets spaces around each argument and a newline at the end for
6432 * echo commands 6000 * echo commands
6546 p += 4; /* termcap option */ 6114 p += 4; /* termcap option */
6547 else 6115 else
6548 while (ASCII_ISALPHA(*p)) 6116 while (ASCII_ISALPHA(*p))
6549 ++p; 6117 ++p;
6550 return p; 6118 return p;
6551 }
6552
6553 /*
6554 * Return the autoload script name for a function or variable name.
6555 * Returns NULL when out of memory.
6556 * Caller must make sure that "name" contains AUTOLOAD_CHAR.
6557 */
6558 char_u *
6559 autoload_name(char_u *name)
6560 {
6561 char_u *p, *q = NULL;
6562 char_u *scriptname;
6563
6564 // Get the script file name: replace '#' with '/', append ".vim".
6565 scriptname = alloc(STRLEN(name) + 14);
6566 if (scriptname == NULL)
6567 return NULL;
6568 STRCPY(scriptname, "autoload/");
6569 STRCAT(scriptname, name);
6570 for (p = scriptname + 9; (p = vim_strchr(p, AUTOLOAD_CHAR)) != NULL;
6571 q = p, ++p)
6572 *p = '/';
6573 STRCPY(q, ".vim");
6574 return scriptname;
6575 }
6576
6577 /*
6578 * If "name" has a package name try autoloading the script for it.
6579 * Return TRUE if a package was loaded.
6580 */
6581 int
6582 script_autoload(
6583 char_u *name,
6584 int reload) /* load script again when already loaded */
6585 {
6586 char_u *p;
6587 char_u *scriptname, *tofree;
6588 int ret = FALSE;
6589 int i;
6590
6591 /* If there is no '#' after name[0] there is no package name. */
6592 p = vim_strchr(name, AUTOLOAD_CHAR);
6593 if (p == NULL || p == name)
6594 return FALSE;
6595
6596 tofree = scriptname = autoload_name(name);
6597 if (scriptname == NULL)
6598 return FALSE;
6599
6600 /* Find the name in the list of previously loaded package names. Skip
6601 * "autoload/", it's always the same. */
6602 for (i = 0; i < ga_loaded.ga_len; ++i)
6603 if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
6604 break;
6605 if (!reload && i < ga_loaded.ga_len)
6606 ret = FALSE; /* was loaded already */
6607 else
6608 {
6609 /* Remember the name if it wasn't loaded already. */
6610 if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
6611 {
6612 ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
6613 tofree = NULL;
6614 }
6615
6616 /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
6617 if (source_runtime(scriptname, 0) == OK)
6618 ret = TRUE;
6619 }
6620
6621 vim_free(tofree);
6622 return ret;
6623 } 6119 }
6624 6120
6625 /* 6121 /*
6626 * Display script name where an item was last set. 6122 * Display script name where an item was last set.
6627 * Should only be invoked when 'verbose' is non-zero. 6123 * Should only be invoked when 'verbose' is non-zero.
7737 did_emsg = FALSE; 7233 did_emsg = FALSE;
7738 7234
7739 prepare_vimvar(VV_KEY, &save_key); 7235 prepare_vimvar(VV_KEY, &save_key);
7740 if (argvars[0].v_type == VAR_DICT) 7236 if (argvars[0].v_type == VAR_DICT)
7741 { 7237 {
7238 set_vim_var_type(VV_KEY, VAR_STRING);
7239
7742 ht = &d->dv_hashtab; 7240 ht = &d->dv_hashtab;
7743 hash_lock(ht); 7241 hash_lock(ht);
7744 todo = (int)ht->ht_used; 7242 todo = (int)ht->ht_used;
7745 for (hi = ht->ht_array; todo > 0; ++hi) 7243 for (hi = ht->ht_array; todo > 0; ++hi)
7746 { 7244 {