xref: /vim-8.2.3635/src/vim9script.c (revision 125ed274)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * vim9script.c: :vim9script, :import, :export and friends
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_EVAL)
17 # include "vim9.h"
18 #endif
19 
20 /*
21  * Return TRUE when currently using Vim9 script syntax.
22  * Does not go up the stack, a ":function" inside vim9script uses legacy
23  * syntax.
24  */
25     int
26 in_vim9script(void)
27 {
28     // "sc_version" is also set when compiling a ":def" function in legacy
29     // script.
30     return current_sctx.sc_version == SCRIPT_VERSION_VIM9
31 		|| (cmdmod.cmod_flags & CMOD_VIM9CMD);
32 }
33 
34 #if defined(FEAT_EVAL) || defined(PROTO)
35 /*
36  * Return TRUE if the current script is Vim9 script.
37  * This also returns TRUE in a legacy function in a Vim9 script.
38  */
39     int
40 current_script_is_vim9(void)
41 {
42     return SCRIPT_ID_VALID(current_sctx.sc_sid)
43 	    && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
44 						       == SCRIPT_VERSION_VIM9;
45 }
46 #endif
47 
48 /*
49  * ":vim9script".
50  */
51     void
52 ex_vim9script(exarg_T *eap UNUSED)
53 {
54 #ifdef FEAT_EVAL
55     int		    sid = current_sctx.sc_sid;
56     scriptitem_T    *si;
57 
58     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
59     {
60 	emsg(_(e_vim9script_can_only_be_used_in_script));
61 	return;
62     }
63 
64     si = SCRIPT_ITEM(sid);
65     if (si->sn_state == SN_STATE_HAD_COMMAND)
66     {
67 	emsg(_(e_vim9script_must_be_first_command_in_script));
68 	return;
69     }
70     if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0)
71     {
72 	semsg(_(e_invarg2), eap->arg);
73 	return;
74     }
75     if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg))
76     {
77 	hashtab_T	*ht = &SCRIPT_VARS(sid);
78 
79 	// Reloading a script without the "noclear" argument: clear
80 	// script-local variables and functions.
81 	hashtab_free_contents(ht);
82 	hash_init(ht);
83 	delete_script_functions(sid);
84 
85 	// old imports and script variables are no longer valid
86 	free_imports_and_script_vars(sid);
87     }
88     si->sn_state = SN_STATE_HAD_COMMAND;
89 
90     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
91     si->sn_version = SCRIPT_VERSION_VIM9;
92 
93     if (STRCMP(p_cpo, CPO_VIM) != 0)
94     {
95 	si->sn_save_cpo = vim_strsave(p_cpo);
96 	set_option_value((char_u *)"cpo", 0L, (char_u *)CPO_VIM, OPT_NO_REDRAW);
97     }
98 #else
99     // No check for this being the first command, it doesn't matter.
100     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
101 #endif
102 }
103 
104 /*
105  * When in Vim9 script give an error and return FAIL.
106  */
107     int
108 not_in_vim9(exarg_T *eap)
109 {
110     if (in_vim9script())
111 	switch (eap->cmdidx)
112 	{
113 	    case CMD_k:
114 		if (eap->addr_count > 0)
115 		{
116 		    emsg(_(e_norange));
117 		    return FAIL;
118 		}
119 		// FALLTHROUGH
120 	    case CMD_append:
121 	    case CMD_change:
122 	    case CMD_insert:
123 	    case CMD_open:
124 	    case CMD_t:
125 	    case CMD_xit:
126 		semsg(_(e_command_not_supported_in_vim9_script_missing_var_str), eap->cmd);
127 		return FAIL;
128 	    default: break;
129 	}
130     return OK;
131 }
132 
133 /*
134  * Give an error message if "p" points at "#{" and return TRUE.
135  * This avoids that using a legacy style #{} dictionary leads to difficult to
136  * understand errors.
137  */
138     int
139 vim9_bad_comment(char_u *p)
140 {
141     if (p[0] == '#' && p[1] == '{' && p[2] != '{')
142     {
143 	emsg(_(e_cannot_use_hash_curly_to_start_comment));
144 	return TRUE;
145     }
146     return FALSE;
147 }
148 
149 /*
150  * Return TRUE if "p" points at a "#" not followed by one '{'.
151  * Does not check for white space.
152  */
153     int
154 vim9_comment_start(char_u *p)
155 {
156     return p[0] == '#' && (p[1] != '{' || p[2] == '{');
157 }
158 
159 #if defined(FEAT_EVAL) || defined(PROTO)
160 
161 /*
162  * ":export let Name: type"
163  * ":export const Name: type"
164  * ":export def Name(..."
165  * ":export class Name ..."
166  */
167     void
168 ex_export(exarg_T *eap)
169 {
170     if (!in_vim9script())
171     {
172 	emsg(_(e_export_can_only_be_used_in_vim9script));
173 	return;
174     }
175 
176     eap->cmd = eap->arg;
177     (void)find_ex_command(eap, NULL, lookup_scriptitem, NULL);
178     switch (eap->cmdidx)
179     {
180 	case CMD_let:
181 	case CMD_var:
182 	case CMD_final:
183 	case CMD_const:
184 	case CMD_def:
185 	// case CMD_class:
186 	    is_export = TRUE;
187 	    do_cmdline(eap->cmd, eap->getline, eap->cookie,
188 						DOCMD_VERBOSE + DOCMD_NOWAIT);
189 
190 	    // The command will reset "is_export" when exporting an item.
191 	    if (is_export)
192 	    {
193 		emsg(_(e_export_with_invalid_argument));
194 		is_export = FALSE;
195 	    }
196 	    break;
197 	default:
198 	    emsg(_(e_invalid_command_after_export));
199 	    break;
200     }
201 }
202 
203 /*
204  * Add a new imported item entry to the current script.
205  */
206     static imported_T *
207 new_imported(garray_T *gap)
208 {
209     if (ga_grow(gap, 1) == OK)
210 	return ((imported_T *)gap->ga_data + gap->ga_len++);
211     return NULL;
212 }
213 
214 /*
215  * Free all imported items in script "sid".
216  */
217     void
218 free_imports_and_script_vars(int sid)
219 {
220     scriptitem_T    *si = SCRIPT_ITEM(sid);
221     int		    idx;
222 
223     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
224     {
225 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
226 
227 	vim_free(imp->imp_name);
228     }
229     ga_clear(&si->sn_imports);
230 
231     free_all_script_vars(si);
232 
233     clear_type_list(&si->sn_type_list);
234 }
235 
236 /*
237  * Mark all imports as possible to redefine.  Used when a script is loaded
238  * again but not cleared.
239  */
240     void
241 mark_imports_for_reload(int sid)
242 {
243     scriptitem_T    *si = SCRIPT_ITEM(sid);
244     int		    idx;
245 
246     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
247     {
248 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
249 
250 	imp->imp_flags |= IMP_FLAGS_RELOAD;
251     }
252 }
253 
254 /*
255  * ":import Item from 'filename'"
256  * ":import Item as Alias from 'filename'"
257  * ":import {Item} from 'filename'".
258  * ":import {Item as Alias} from 'filename'"
259  * ":import {Item, Item} from 'filename'"
260  * ":import {Item, Item as Alias} from 'filename'"
261  *
262  * ":import * as Name from 'filename'"
263  */
264     void
265 ex_import(exarg_T *eap)
266 {
267     char_u	*cmd_end;
268     evalarg_T	evalarg;
269 
270     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
271     {
272 	emsg(_(e_import_can_only_be_used_in_script));
273 	return;
274     }
275     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
276 
277     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
278 							       &evalarg, NULL);
279     if (cmd_end != NULL)
280 	eap->nextcmd = check_nextcmd(cmd_end);
281     clear_evalarg(&evalarg, eap);
282 }
283 
284 /*
285  * Find an exported item in "sid" matching the name at "*argp".
286  * When it is a variable return the index.
287  * When it is a user function return "*ufunc".
288  * When not found returns -1 and "*ufunc" is NULL.
289  */
290     int
291 find_exported(
292 	int	    sid,
293 	char_u	    *name,
294 	ufunc_T	    **ufunc,
295 	type_T	    **type,
296 	cctx_T	    *cctx,
297 	int	    verbose)
298 {
299     int		idx = -1;
300     svar_T	*sv;
301     scriptitem_T *script = SCRIPT_ITEM(sid);
302 
303     // Find name in "script".
304     idx = get_script_item_idx(sid, name, 0, cctx);
305     if (idx >= 0)
306     {
307 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
308 	if (!sv->sv_export)
309 	{
310 	    if (verbose)
311 		semsg(_(e_item_not_exported_in_script_str), name);
312 	    return -1;
313 	}
314 	*type = sv->sv_type;
315 	*ufunc = NULL;
316     }
317     else
318     {
319 	char_u	buffer[200];
320 	char_u	*funcname;
321 
322 	// it could be a user function.
323 	if (STRLEN(name) < sizeof(buffer) - 15)
324 	    funcname = buffer;
325 	else
326 	{
327 	    funcname = alloc(STRLEN(name) + 15);
328 	    if (funcname == NULL)
329 		return -1;
330 	}
331 	funcname[0] = K_SPECIAL;
332 	funcname[1] = KS_EXTRA;
333 	funcname[2] = (int)KE_SNR;
334 	sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
335 	*ufunc = find_func(funcname, FALSE, NULL);
336 	if (funcname != buffer)
337 	    vim_free(funcname);
338 
339 	if (*ufunc == NULL)
340 	{
341 	    if (verbose)
342 		semsg(_(e_item_not_found_in_script_str), name);
343 	    return -1;
344 	}
345 	else if (((*ufunc)->uf_flags & FC_EXPORT) == 0)
346 	{
347 	    if (verbose)
348 		semsg(_(e_item_not_exported_in_script_str), name);
349 	    *ufunc = NULL;
350 	    return -1;
351 	}
352     }
353 
354     return idx;
355 }
356 
357 /*
358  * Handle an ":import" command and add the resulting imported_T to "gap", when
359  * not NULL, or script "import_sid" sn_imports.
360  * "cctx" is NULL at the script level.
361  * Returns a pointer to after the command or NULL in case of failure
362  */
363     char_u *
364 handle_import(
365 	char_u	    *arg_start,
366 	garray_T    *gap,
367 	int	    import_sid,
368 	evalarg_T   *evalarg,
369 	void	    *cctx)
370 {
371     char_u	*arg = arg_start;
372     char_u	*cmd_end = NULL;
373     int		ret = FAIL;
374     typval_T	tv;
375     int		sid = -1;
376     int		res;
377     int		mult = FALSE;
378     garray_T	names;
379     garray_T	as_names;
380 
381     ga_init2(&names, sizeof(char_u *), 10);
382     ga_init2(&as_names, sizeof(char_u *), 10);
383     if (*arg == '{')
384     {
385 	// "import {item, item} from ..."
386 	mult = TRUE;
387 	arg = skipwhite_and_linebreak(arg + 1, evalarg);
388     }
389 
390     for (;;)
391     {
392 	char_u	    *p = arg;
393 	int	    had_comma = FALSE;
394 	char_u	    *as_name = NULL;
395 
396 	// accept "*" or "Name"
397 	if (!mult && arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
398 	    ++arg;
399 	else
400 	    while (eval_isnamec(*arg))
401 		++arg;
402 	if (p == arg)
403 	    break;
404 	if (ga_grow(&names, 1) == FAIL || ga_grow(&as_names, 1) == FAIL)
405 	    goto erret;
406 	((char_u **)names.ga_data)[names.ga_len] = vim_strnsave(p, arg - p);
407 	++names.ga_len;
408 
409 	arg = skipwhite_and_linebreak(arg, evalarg);
410 	if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
411 	{
412 	    // skip over "as Name "; no line break allowed after "as"
413 	    arg = skipwhite(arg + 2);
414 	    p = arg;
415 	    if (eval_isnamec1(*arg))
416 		while (eval_isnamec(*arg))
417 		    ++arg;
418 	    if (check_defined(p, arg - p, cctx, FALSE) == FAIL)
419 		goto erret;
420 	    as_name = vim_strnsave(p, arg - p);
421 	    arg = skipwhite_and_linebreak(arg, evalarg);
422 	}
423 	else if (*arg_start == '*')
424 	{
425 	    emsg(_(e_missing_as_after_star));
426 	    goto erret;
427 	}
428 	// without "as Name" the as_names entry is NULL
429 	((char_u **)as_names.ga_data)[as_names.ga_len] = as_name;
430 	++as_names.ga_len;
431 
432 	if (!mult)
433 	    break;
434 	if (*arg == ',')
435 	{
436 	    had_comma = TRUE;
437 	    ++arg;
438 	}
439 	arg = skipwhite_and_linebreak(arg, evalarg);
440 	if (*arg == '}')
441 	{
442 	    ++arg;
443 	    break;
444 	}
445 	if (!had_comma)
446 	{
447 	    emsg(_(e_missing_comma_in_import));
448 	    goto erret;
449 	}
450     }
451     arg = skipwhite_and_linebreak(arg, evalarg);
452 
453     if (names.ga_len == 0)
454     {
455 	emsg(_(e_syntax_error_in_import));
456 	goto erret;
457     }
458 
459     if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
460     {
461 	emsg(_(e_missing_from));
462 	goto erret;
463     }
464 
465     arg = skipwhite_and_linebreak(arg + 4, evalarg);
466     tv.v_type = VAR_UNKNOWN;
467     // TODO: should we accept any expression?
468     if (*arg == '\'')
469 	ret = eval_lit_string(&arg, &tv, TRUE);
470     else if (*arg == '"')
471 	ret = eval_string(&arg, &tv, TRUE);
472     if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
473     {
474 	emsg(_(e_invalid_string_after_from));
475 	goto erret;
476     }
477     cmd_end = arg;
478 
479     /*
480      * find script file
481      */
482     if (*tv.vval.v_string == '.')
483     {
484 	size_t		len;
485 	scriptitem_T	*si = SCRIPT_ITEM(current_sctx.sc_sid);
486 	char_u		*tail = gettail(si->sn_name);
487 	char_u		*from_name;
488 
489 	// Relative to current script: "./name.vim", "../../name.vim".
490 	len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
491 	from_name = alloc((int)len);
492 	if (from_name == NULL)
493 	{
494 	    clear_tv(&tv);
495 	    goto erret;
496 	}
497 	vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
498 	add_pathsep(from_name);
499 	STRCAT(from_name, tv.vval.v_string);
500 	simplify_filename(from_name);
501 
502 	res = do_source(from_name, FALSE, DOSO_NONE, &sid);
503 	vim_free(from_name);
504     }
505     else if (mch_isFullName(tv.vval.v_string))
506     {
507 	// Absolute path: "/tmp/name.vim"
508 	res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
509     }
510     else
511     {
512 	size_t	    len = 7 + STRLEN(tv.vval.v_string) + 1;
513 	char_u	    *from_name;
514 
515 	// Find file in "import" subdirs in 'runtimepath'.
516 	from_name = alloc((int)len);
517 	if (from_name == NULL)
518 	{
519 	    clear_tv(&tv);
520 	    goto erret;
521 	}
522 	vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
523 	res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
524 	vim_free(from_name);
525     }
526 
527     if (res == FAIL || sid <= 0)
528     {
529 	semsg(_(e_could_not_import_str), tv.vval.v_string);
530 	clear_tv(&tv);
531 	goto erret;
532     }
533     clear_tv(&tv);
534 
535     if (*arg_start == '*')
536     {
537 	imported_T  *imported;
538 	char_u	    *as_name = ((char_u **)as_names.ga_data)[0];
539 
540 	// "import * as That"
541 	imported = find_imported(as_name, STRLEN(as_name), cctx);
542 	if (imported != NULL && imported->imp_sid == sid)
543 	{
544 	    if (imported->imp_flags & IMP_FLAGS_RELOAD)
545 		// import already defined on a previous script load
546 		imported->imp_flags &= ~IMP_FLAGS_RELOAD;
547 	    else
548 	    {
549 		semsg(_(e_name_already_defined_str), as_name);
550 		goto erret;
551 	    }
552 	}
553 
554 	imported = new_imported(gap != NULL ? gap
555 					: &SCRIPT_ITEM(import_sid)->sn_imports);
556 	if (imported == NULL)
557 	    goto erret;
558 	imported->imp_name = as_name;
559 	((char_u **)as_names.ga_data)[0] = NULL;
560 	imported->imp_sid = sid;
561 	imported->imp_flags = IMP_FLAGS_STAR;
562     }
563     else
564     {
565 	int i;
566 
567 	arg = arg_start;
568 	if (*arg == '{')
569 	    arg = skipwhite(arg + 1);
570 	for (i = 0; i < names.ga_len; ++i)
571 	{
572 	    char_u	*name = ((char_u **)names.ga_data)[i];
573 	    char_u	*as_name = ((char_u **)as_names.ga_data)[i];
574 	    size_t	len = STRLEN(name);
575 	    int		idx;
576 	    imported_T	*imported;
577 	    ufunc_T	*ufunc = NULL;
578 	    type_T	*type;
579 
580 	    idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE);
581 
582 	    if (idx < 0 && ufunc == NULL)
583 		goto erret;
584 
585 	    // If already imported with the same propertis and the
586 	    // IMP_FLAGS_RELOAD set then we keep that entry.  Otherwise create
587 	    // a new one (and give an error for an existing import).
588 	    imported = find_imported(name, len, cctx);
589 	    if (imported != NULL
590 		    && (imported->imp_flags & IMP_FLAGS_RELOAD)
591 		    && imported->imp_sid == sid
592 		    && (idx >= 0
593 			? (equal_type(imported->imp_type, type)
594 			    && imported->imp_var_vals_idx == idx)
595 			: (equal_type(imported->imp_type, ufunc->uf_func_type)
596 			    && STRCMP(imported->imp_funcname,
597 							ufunc->uf_name) == 0)))
598 	    {
599 		imported->imp_flags &= ~IMP_FLAGS_RELOAD;
600 	    }
601 	    else
602 	    {
603 		if (check_defined(name, len, cctx, FALSE) == FAIL)
604 		    goto erret;
605 
606 		imported = new_imported(gap != NULL ? gap
607 				       : &SCRIPT_ITEM(import_sid)->sn_imports);
608 		if (imported == NULL)
609 		    goto erret;
610 
611 		if (as_name == NULL)
612 		{
613 		    imported->imp_name = name;
614 		    ((char_u **)names.ga_data)[i] = NULL;
615 		}
616 		else
617 		{
618 		    // "import This as That ..."
619 		    imported->imp_name = as_name;
620 		    ((char_u **)as_names.ga_data)[i] = NULL;
621 		}
622 		imported->imp_sid = sid;
623 		if (idx >= 0)
624 		{
625 		    imported->imp_type = type;
626 		    imported->imp_var_vals_idx = idx;
627 		}
628 		else
629 		{
630 		    imported->imp_type = ufunc->uf_func_type;
631 		    imported->imp_funcname = ufunc->uf_name;
632 		}
633 	    }
634 	}
635     }
636 erret:
637     ga_clear_strings(&names);
638     ga_clear_strings(&as_names);
639     return cmd_end;
640 }
641 
642 /*
643  * Declare a script-local variable without init: "let var: type".
644  * "const" is an error since the value is missing.
645  * Returns a pointer to after the type.
646  */
647     char_u *
648 vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
649 {
650     char_u	    *p;
651     char_u	    *name;
652     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
653     type_T	    *type;
654     typval_T	    init_tv;
655 
656     if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const)
657     {
658 	if (eap->cmdidx == CMD_final)
659 	    emsg(_(e_final_requires_a_value));
660 	else
661 	    emsg(_(e_const_requires_a_value));
662 	return arg + STRLEN(arg);
663     }
664 
665     // Check for valid starting character.
666     if (!eval_isnamec1(*arg))
667     {
668 	semsg(_(e_invarg2), arg);
669 	return arg + STRLEN(arg);
670     }
671 
672     for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
673 	if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
674 	    break;
675 
676     if (*p != ':')
677     {
678 	emsg(_(e_type_or_initialization_required));
679 	return arg + STRLEN(arg);
680     }
681     if (!VIM_ISWHITE(p[1]))
682     {
683 	semsg(_(e_white_space_required_after_str_str), ":", p);
684 	return arg + STRLEN(arg);
685     }
686     name = vim_strnsave(arg, p - arg);
687 
688     // parse type
689     p = skipwhite(p + 1);
690     type = parse_type(&p, &si->sn_type_list, TRUE);
691     if (type == NULL)
692     {
693 	vim_free(name);
694 	return p;
695     }
696 
697     // Create the variable with 0/NULL value.
698     CLEAR_FIELD(init_tv);
699     if (type->tt_type == VAR_ANY)
700 	// A variable of type "any" is not possible, just use zero instead
701 	init_tv.v_type = VAR_NUMBER;
702     else
703 	init_tv.v_type = type->tt_type;
704     set_var_const(name, type, &init_tv, FALSE, 0, 0);
705 
706     vim_free(name);
707     return p;
708 }
709 
710 /*
711  * Vim9 part of adding a script variable: add it to sn_all_vars (lookup by name
712  * with a hashtable) and sn_var_vals (lookup by index).
713  * When "create" is TRUE this is a new variable, otherwise find and update an
714  * existing variable.
715  * "flags" can have ASSIGN_FINAL or ASSIGN_CONST.
716  * When "*type" is NULL use "tv" for the type and update "*type".
717  */
718     void
719 update_vim9_script_var(
720 	int	    create,
721 	dictitem_T  *di,
722 	int	    flags,
723 	typval_T    *tv,
724 	type_T	    **type)
725 {
726     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
727     hashitem_T	    *hi;
728     svar_T	    *sv;
729 
730     if (create)
731     {
732 	sallvar_T	    *newsav;
733 
734 	// Store a pointer to the typval_T, so that it can be found by index
735 	// instead of using a hastab lookup.
736 	if (ga_grow(&si->sn_var_vals, 1) == FAIL)
737 	    return;
738 
739 	sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
740 	newsav = (sallvar_T *)alloc_clear(
741 				       sizeof(sallvar_T) + STRLEN(di->di_key));
742 	if (newsav == NULL)
743 	    return;
744 
745 	sv->sv_tv = &di->di_tv;
746 	sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
747 				   : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
748 	sv->sv_export = is_export;
749 	newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
750 	++si->sn_var_vals.ga_len;
751 	STRCPY(&newsav->sav_key, di->di_key);
752 	sv->sv_name = newsav->sav_key;
753 	newsav->sav_di = di;
754 	newsav->sav_block_id = si->sn_current_block_id;
755 
756 	hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
757 	if (!HASHITEM_EMPTY(hi))
758 	{
759 	    sallvar_T *sav = HI2SAV(hi);
760 
761 	    // variable with this name exists in another block
762 	    while (sav->sav_next != NULL)
763 		sav = sav->sav_next;
764 	    sav->sav_next = newsav;
765 	}
766 	else
767 	    // new variable name
768 	    hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
769     }
770     else
771     {
772 	sv = find_typval_in_script(&di->di_tv);
773     }
774     if (sv != NULL)
775     {
776 	if (*type == NULL)
777 	    *type = typval2type(tv, get_copyID(), &si->sn_type_list);
778 	sv->sv_type = *type;
779     }
780 
781     // let ex_export() know the export worked.
782     is_export = FALSE;
783 }
784 
785 /*
786  * Hide a script variable when leaving a block.
787  * "idx" is de index in sn_var_vals.
788  * When "func_defined" is non-zero then a function was defined in this block,
789  * the variable may be accessed by it.  Otherwise the variable can be cleared.
790  */
791     void
792 hide_script_var(scriptitem_T *si, int idx, int func_defined)
793 {
794     svar_T	*sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
795     hashtab_T	*script_ht = get_script_local_ht();
796     hashtab_T	*all_ht = &si->sn_all_vars.dv_hashtab;
797     hashitem_T	*script_hi;
798     hashitem_T	*all_hi;
799 
800     // Remove a variable declared inside the block, if it still exists.
801     // If it was added in a nested block it will already have been removed.
802     // The typval is moved into the sallvar_T.
803     script_hi = hash_find(script_ht, sv->sv_name);
804     all_hi = hash_find(all_ht, sv->sv_name);
805     if (!HASHITEM_EMPTY(script_hi) && !HASHITEM_EMPTY(all_hi))
806     {
807 	dictitem_T	*di = HI2DI(script_hi);
808 	sallvar_T	*sav = HI2SAV(all_hi);
809 	sallvar_T	*sav_prev = NULL;
810 
811 	// There can be multiple entries with the same name in different
812 	// blocks, find the right one.
813 	while (sav != NULL && sav->sav_var_vals_idx != idx)
814 	{
815 	    sav_prev = sav;
816 	    sav = sav->sav_next;
817 	}
818 	if (sav != NULL)
819 	{
820 	    if (func_defined)
821 	    {
822 		// move the typval from the dictitem to the sallvar
823 		sav->sav_tv = di->di_tv;
824 		di->di_tv.v_type = VAR_UNKNOWN;
825 		sav->sav_flags = di->di_flags;
826 		sav->sav_di = NULL;
827 		sv->sv_tv = &sav->sav_tv;
828 	    }
829 	    else
830 	    {
831 		if (sav_prev == NULL)
832 		    hash_remove(all_ht, all_hi);
833 		else
834 		    sav_prev->sav_next = sav->sav_next;
835 		sv->sv_name = NULL;
836 		vim_free(sav);
837 	    }
838 	    delete_var(script_ht, script_hi);
839 	}
840     }
841 }
842 
843 /*
844  * Free the script variables from "sn_all_vars".
845  */
846     void
847 free_all_script_vars(scriptitem_T *si)
848 {
849     int		todo;
850     hashtab_T	*ht = &si->sn_all_vars.dv_hashtab;
851     hashitem_T	*hi;
852     sallvar_T	*sav;
853     sallvar_T	*sav_next;
854 
855     hash_lock(ht);
856     todo = (int)ht->ht_used;
857     for (hi = ht->ht_array; todo > 0; ++hi)
858     {
859 	if (!HASHITEM_EMPTY(hi))
860 	{
861 	    --todo;
862 
863 	    // Free the variable.  Don't remove it from the hashtab, ht_array
864 	    // might change then.  hash_clear() takes care of it later.
865 	    sav = HI2SAV(hi);
866 	    while (sav != NULL)
867 	    {
868 		sav_next = sav->sav_next;
869 		if (sav->sav_di == NULL)
870 		    clear_tv(&sav->sav_tv);
871 		vim_free(sav);
872 		sav = sav_next;
873 	    }
874 	}
875     }
876     hash_clear(ht);
877     hash_init(ht);
878 
879     ga_clear(&si->sn_var_vals);
880 
881     // existing commands using script variable indexes are no longer valid
882     si->sn_script_seq = current_sctx.sc_seq;
883 }
884 
885 /*
886  * Find the script-local variable that links to "dest".
887  * Returns NULL if not found.
888  */
889     svar_T *
890 find_typval_in_script(typval_T *dest)
891 {
892     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
893     int		    idx;
894 
895     if (si->sn_version != SCRIPT_VERSION_VIM9)
896 	// legacy script doesn't store variable types
897 	return NULL;
898 
899     // Find the svar_T in sn_var_vals.
900     for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
901     {
902 	svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
903 
904 	// If "sv_name" is NULL the variable was hidden when leaving a block,
905 	// don't check "sv_tv" then, it might be used for another variable now.
906 	if (sv->sv_name != NULL && sv->sv_tv == dest)
907 	    return sv;
908     }
909     iemsg("find_typval_in_script(): not found");
910     return NULL;
911 }
912 
913 /*
914  * Check if the type of script variable "dest" allows assigning "value".
915  * If needed convert "value" to a bool.
916  */
917     int
918 check_script_var_type(
919 	typval_T    *dest,
920 	typval_T    *value,
921 	char_u	    *name,
922 	where_T	    where)
923 {
924     svar_T  *sv = find_typval_in_script(dest);
925     int	    ret;
926 
927     if (sv != NULL)
928     {
929 	if (sv->sv_const != 0)
930 	{
931 	    semsg(_(e_readonlyvar), name);
932 	    return FAIL;
933 	}
934 	ret = check_typval_type(sv->sv_type, value, where);
935 	if (ret == OK && need_convert_to_bool(sv->sv_type, value))
936 	{
937 	    int	val = tv2bool(value);
938 
939 	    clear_tv(value);
940 	    value->v_type = VAR_BOOL;
941 	    value->v_lock = 0;
942 	    value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
943 	}
944 	return ret;
945     }
946 
947     return OK; // not really
948 }
949 
950 #endif // FEAT_EVAL
951