xref: /vim-8.2.3635/src/vim9script.c (revision cbb6bdcd)
18a7d6542SBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
28a7d6542SBram Moolenaar  *
38a7d6542SBram Moolenaar  * VIM - Vi IMproved	by Bram Moolenaar
48a7d6542SBram Moolenaar  *
58a7d6542SBram Moolenaar  * Do ":help uganda"  in Vim to read copying and usage conditions.
68a7d6542SBram Moolenaar  * Do ":help credits" in Vim to see a list of people who contributed.
78a7d6542SBram Moolenaar  * See README.txt for an overview of the Vim source code.
88a7d6542SBram Moolenaar  */
98a7d6542SBram Moolenaar 
108a7d6542SBram Moolenaar /*
118a7d6542SBram Moolenaar  * vim9script.c: :vim9script, :import, :export and friends
128a7d6542SBram Moolenaar  */
138a7d6542SBram Moolenaar 
148a7d6542SBram Moolenaar #include "vim.h"
158a7d6542SBram Moolenaar 
168a7d6542SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
178a7d6542SBram Moolenaar 
188a7d6542SBram Moolenaar #include "vim9.h"
198a7d6542SBram Moolenaar 
209721fb4eSBram Moolenaar static char e_needs_vim9[] = N_("E1042: export can only be used in vim9script");
218a7d6542SBram Moolenaar 
228a7d6542SBram Moolenaar     int
238a7d6542SBram Moolenaar in_vim9script(void)
248a7d6542SBram Moolenaar {
258a7d6542SBram Moolenaar     // TODO: go up the stack?
268a7d6542SBram Moolenaar     return current_sctx.sc_version == SCRIPT_VERSION_VIM9;
278a7d6542SBram Moolenaar }
288a7d6542SBram Moolenaar 
298a7d6542SBram Moolenaar /*
308a7d6542SBram Moolenaar  * ":vim9script".
318a7d6542SBram Moolenaar  */
328a7d6542SBram Moolenaar     void
338a7d6542SBram Moolenaar ex_vim9script(exarg_T *eap)
348a7d6542SBram Moolenaar {
35101f4810SBram Moolenaar     scriptitem_T    *si;
368a7d6542SBram Moolenaar 
378a7d6542SBram Moolenaar     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
388a7d6542SBram Moolenaar     {
398a7d6542SBram Moolenaar 	emsg(_("E1038: vim9script can only be used in a script"));
408a7d6542SBram Moolenaar 	return;
418a7d6542SBram Moolenaar     }
42101f4810SBram Moolenaar     si = SCRIPT_ITEM(current_sctx.sc_sid);
438a7d6542SBram Moolenaar     if (si->sn_had_command)
448a7d6542SBram Moolenaar     {
458a7d6542SBram Moolenaar 	emsg(_("E1039: vim9script must be the first command in a script"));
468a7d6542SBram Moolenaar 	return;
478a7d6542SBram Moolenaar     }
488a7d6542SBram Moolenaar     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
498a7d6542SBram Moolenaar     si->sn_version = SCRIPT_VERSION_VIM9;
508a7d6542SBram Moolenaar     si->sn_had_command = TRUE;
518a7d6542SBram Moolenaar 
528a7d6542SBram Moolenaar     if (STRCMP(p_cpo, CPO_VIM) != 0)
538a7d6542SBram Moolenaar     {
548a7d6542SBram Moolenaar 	si->sn_save_cpo = p_cpo;
558a7d6542SBram Moolenaar 	p_cpo = vim_strsave((char_u *)CPO_VIM);
568a7d6542SBram Moolenaar     }
57227a69deSBram Moolenaar }
588a7d6542SBram Moolenaar 
598a7d6542SBram Moolenaar /*
608a7d6542SBram Moolenaar  * ":export let Name: type"
618a7d6542SBram Moolenaar  * ":export const Name: type"
628a7d6542SBram Moolenaar  * ":export def Name(..."
638a7d6542SBram Moolenaar  * ":export class Name ..."
648a7d6542SBram Moolenaar  *
658a7d6542SBram Moolenaar  * ":export {Name, ...}"
668a7d6542SBram Moolenaar  */
678a7d6542SBram Moolenaar     void
6809689a02SBram Moolenaar ex_export(exarg_T *eap)
698a7d6542SBram Moolenaar {
708a7d6542SBram Moolenaar     if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
718a7d6542SBram Moolenaar     {
728a7d6542SBram Moolenaar 	emsg(_(e_needs_vim9));
738a7d6542SBram Moolenaar 	return;
748a7d6542SBram Moolenaar     }
758a7d6542SBram Moolenaar 
768a7d6542SBram Moolenaar     eap->cmd = eap->arg;
778a7d6542SBram Moolenaar     (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
788a7d6542SBram Moolenaar     switch (eap->cmdidx)
798a7d6542SBram Moolenaar     {
808a7d6542SBram Moolenaar 	case CMD_let:
818a7d6542SBram Moolenaar 	case CMD_const:
828a7d6542SBram Moolenaar 	case CMD_def:
838a7d6542SBram Moolenaar 	// case CMD_class:
848a7d6542SBram Moolenaar 	    is_export = TRUE;
858a7d6542SBram Moolenaar 	    do_cmdline(eap->cmd, eap->getline, eap->cookie,
868a7d6542SBram Moolenaar 						DOCMD_VERBOSE + DOCMD_NOWAIT);
878a7d6542SBram Moolenaar 
888a7d6542SBram Moolenaar 	    // The command will reset "is_export" when exporting an item.
898a7d6542SBram Moolenaar 	    if (is_export)
908a7d6542SBram Moolenaar 	    {
918a7d6542SBram Moolenaar 		emsg(_("E1044: export with invalid argument"));
928a7d6542SBram Moolenaar 		is_export = FALSE;
938a7d6542SBram Moolenaar 	    }
948a7d6542SBram Moolenaar 	    break;
958a7d6542SBram Moolenaar 	default:
968a7d6542SBram Moolenaar 	    emsg(_("E1043: Invalid command after :export"));
978a7d6542SBram Moolenaar 	    break;
988a7d6542SBram Moolenaar     }
998a7d6542SBram Moolenaar }
1008a7d6542SBram Moolenaar 
1018a7d6542SBram Moolenaar /*
1028a7d6542SBram Moolenaar  * Add a new imported item entry to the current script.
1038a7d6542SBram Moolenaar  */
1048a7d6542SBram Moolenaar     static imported_T *
1058a7d6542SBram Moolenaar new_imported(garray_T *gap)
1068a7d6542SBram Moolenaar {
1078a7d6542SBram Moolenaar     if (ga_grow(gap, 1) == OK)
1088a7d6542SBram Moolenaar 	return ((imported_T *)gap->ga_data + gap->ga_len++);
1098a7d6542SBram Moolenaar     return NULL;
1108a7d6542SBram Moolenaar }
1118a7d6542SBram Moolenaar 
1128a7d6542SBram Moolenaar /*
1138a7d6542SBram Moolenaar  * Free all imported items in script "sid".
1148a7d6542SBram Moolenaar  */
1158a7d6542SBram Moolenaar     void
1168a7d6542SBram Moolenaar free_imports(int sid)
1178a7d6542SBram Moolenaar {
11821b9e977SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(sid);
1198a7d6542SBram Moolenaar     int		    idx;
1208a7d6542SBram Moolenaar 
1218a7d6542SBram Moolenaar     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
1228a7d6542SBram Moolenaar     {
12320431c9dSBram Moolenaar 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
1248a7d6542SBram Moolenaar 
1258a7d6542SBram Moolenaar 	vim_free(imp->imp_name);
1268a7d6542SBram Moolenaar     }
1278a7d6542SBram Moolenaar     ga_clear(&si->sn_imports);
12820431c9dSBram Moolenaar     ga_clear(&si->sn_var_vals);
12920431c9dSBram Moolenaar     ga_clear(&si->sn_type_list);
1308a7d6542SBram Moolenaar }
1318a7d6542SBram Moolenaar 
1328a7d6542SBram Moolenaar /*
1338a7d6542SBram Moolenaar  * ":import Item from 'filename'"
1348a7d6542SBram Moolenaar  * ":import Item as Alias from 'filename'"
1358a7d6542SBram Moolenaar  * ":import {Item} from 'filename'".
1368a7d6542SBram Moolenaar  * ":import {Item as Alias} from 'filename'"
1378a7d6542SBram Moolenaar  * ":import {Item, Item} from 'filename'"
1388a7d6542SBram Moolenaar  * ":import {Item, Item as Alias} from 'filename'"
1398a7d6542SBram Moolenaar  *
1408a7d6542SBram Moolenaar  * ":import * as Name from 'filename'"
1418a7d6542SBram Moolenaar  */
1428a7d6542SBram Moolenaar     void
1438a7d6542SBram Moolenaar ex_import(exarg_T *eap)
1448a7d6542SBram Moolenaar {
145101f4810SBram Moolenaar     char_u	*cmd_end;
1461c991144SBram Moolenaar     evalarg_T	evalarg;
1478a7d6542SBram Moolenaar 
148101f4810SBram Moolenaar     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
149101f4810SBram Moolenaar     {
150101f4810SBram Moolenaar 	emsg(_("E1094: import can only be used in a script"));
151101f4810SBram Moolenaar 	return;
152101f4810SBram Moolenaar     }
1531c991144SBram Moolenaar     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
154101f4810SBram Moolenaar 
1551c991144SBram Moolenaar     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
1561c991144SBram Moolenaar 							       &evalarg, NULL);
1578a7d6542SBram Moolenaar     if (cmd_end != NULL)
1588a7d6542SBram Moolenaar 	eap->nextcmd = check_nextcmd(cmd_end);
1591c991144SBram Moolenaar     clear_evalarg(&evalarg, eap);
1608a7d6542SBram Moolenaar }
1618a7d6542SBram Moolenaar 
1628a7d6542SBram Moolenaar /*
163f2d5c240SBram Moolenaar  * Find an exported item in "sid" matching the name at "*argp".
164f2d5c240SBram Moolenaar  * When it is a variable return the index.
165f2d5c240SBram Moolenaar  * When it is a user function return "*ufunc".
166f2d5c240SBram Moolenaar  * When not found returns -1 and "*ufunc" is NULL.
167f2d5c240SBram Moolenaar  */
168f2d5c240SBram Moolenaar     int
169f2d5c240SBram Moolenaar find_exported(
170f2d5c240SBram Moolenaar 	int	    sid,
1711c991144SBram Moolenaar 	char_u	    *name,
172f2d5c240SBram Moolenaar 	ufunc_T	    **ufunc,
173f2d5c240SBram Moolenaar 	type_T	    **type)
174f2d5c240SBram Moolenaar {
175f2d5c240SBram Moolenaar     int		idx = -1;
176f2d5c240SBram Moolenaar     svar_T	*sv;
177f2d5c240SBram Moolenaar     scriptitem_T *script = SCRIPT_ITEM(sid);
178f2d5c240SBram Moolenaar 
179f2d5c240SBram Moolenaar     // find name in "script"
180f2d5c240SBram Moolenaar     // TODO: also find script-local user function
181f2d5c240SBram Moolenaar     idx = get_script_item_idx(sid, name, FALSE);
182f2d5c240SBram Moolenaar     if (idx >= 0)
183f2d5c240SBram Moolenaar     {
184f2d5c240SBram Moolenaar 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
185f2d5c240SBram Moolenaar 	if (!sv->sv_export)
186f2d5c240SBram Moolenaar 	{
187f2d5c240SBram Moolenaar 	    semsg(_("E1049: Item not exported in script: %s"), name);
188f2d5c240SBram Moolenaar 	    return -1;
189f2d5c240SBram Moolenaar 	}
190f2d5c240SBram Moolenaar 	*type = sv->sv_type;
191f2d5c240SBram Moolenaar 	*ufunc = NULL;
192f2d5c240SBram Moolenaar     }
193f2d5c240SBram Moolenaar     else
194f2d5c240SBram Moolenaar     {
195f2d5c240SBram Moolenaar 	char_u	buffer[200];
196f2d5c240SBram Moolenaar 	char_u	*funcname;
197f2d5c240SBram Moolenaar 
198f2d5c240SBram Moolenaar 	// it could be a user function.
199f2d5c240SBram Moolenaar 	if (STRLEN(name) < sizeof(buffer) - 10)
200f2d5c240SBram Moolenaar 	    funcname = buffer;
201f2d5c240SBram Moolenaar 	else
202f2d5c240SBram Moolenaar 	{
203f2d5c240SBram Moolenaar 	    funcname = alloc(STRLEN(name) + 10);
204f2d5c240SBram Moolenaar 	    if (funcname == NULL)
205f2d5c240SBram Moolenaar 		return -1;
206f2d5c240SBram Moolenaar 	}
207f2d5c240SBram Moolenaar 	funcname[0] = K_SPECIAL;
208f2d5c240SBram Moolenaar 	funcname[1] = KS_EXTRA;
209f2d5c240SBram Moolenaar 	funcname[2] = (int)KE_SNR;
210f2d5c240SBram Moolenaar 	sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
2114c17ad94SBram Moolenaar 	*ufunc = find_func(funcname, FALSE, NULL);
212f2d5c240SBram Moolenaar 	if (funcname != buffer)
213f2d5c240SBram Moolenaar 	    vim_free(funcname);
214f2d5c240SBram Moolenaar 
215f2d5c240SBram Moolenaar 	if (*ufunc == NULL)
216f2d5c240SBram Moolenaar 	{
217f2d5c240SBram Moolenaar 	    semsg(_("E1048: Item not found in script: %s"), name);
218f2d5c240SBram Moolenaar 	    return -1;
219f2d5c240SBram Moolenaar 	}
220f2d5c240SBram Moolenaar     }
221f2d5c240SBram Moolenaar 
222f2d5c240SBram Moolenaar     return idx;
223f2d5c240SBram Moolenaar }
224f2d5c240SBram Moolenaar 
225f2d5c240SBram Moolenaar /*
2268a7d6542SBram Moolenaar  * Handle an ":import" command and add the resulting imported_T to "gap", when
2278a7d6542SBram Moolenaar  * not NULL, or script "import_sid" sn_imports.
2288a7d6542SBram Moolenaar  * Returns a pointer to after the command or NULL in case of failure
2298a7d6542SBram Moolenaar  */
2308a7d6542SBram Moolenaar     char_u *
2311c991144SBram Moolenaar handle_import(
2321c991144SBram Moolenaar 	char_u	    *arg_start,
2331c991144SBram Moolenaar 	garray_T    *gap,
2341c991144SBram Moolenaar 	int	    import_sid,
2351c991144SBram Moolenaar 	evalarg_T   *evalarg,
2361c991144SBram Moolenaar 	void	    *cctx)
2378a7d6542SBram Moolenaar {
2388a7d6542SBram Moolenaar     char_u	*arg = arg_start;
2391c991144SBram Moolenaar     char_u	*cmd_end = NULL;
2401c991144SBram Moolenaar     char_u	*as_name = NULL;
2418a7d6542SBram Moolenaar     int		ret = FAIL;
2428a7d6542SBram Moolenaar     typval_T	tv;
2438a7d6542SBram Moolenaar     int		sid = -1;
2448a7d6542SBram Moolenaar     int		res;
2451c991144SBram Moolenaar     garray_T	names;
2461c991144SBram Moolenaar     static char e_import_syntax[] = N_("E1047: syntax error in import");
2478a7d6542SBram Moolenaar 
2481c991144SBram Moolenaar     ga_init2(&names, sizeof(char_u *), 10);
2498a7d6542SBram Moolenaar     if (*arg == '{')
2508a7d6542SBram Moolenaar     {
2511c991144SBram Moolenaar 	// "import {item, item} from ..."
2521c991144SBram Moolenaar 	arg = skipwhite_and_linebreak(arg + 1, evalarg);
2531c991144SBram Moolenaar 	for (;;)
2541c991144SBram Moolenaar 	{
2551c991144SBram Moolenaar 	    char_u  *p = arg;
2561c991144SBram Moolenaar 	    int	    had_comma = FALSE;
2571c991144SBram Moolenaar 
2581c991144SBram Moolenaar 	    while (eval_isnamec(*arg))
2598a7d6542SBram Moolenaar 		++arg;
2601c991144SBram Moolenaar 	    if (p == arg)
2611c991144SBram Moolenaar 		break;
2621c991144SBram Moolenaar 	    if (ga_grow(&names, 1) == FAIL)
2631c991144SBram Moolenaar 		goto erret;
2641c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[names.ga_len] =
2651c991144SBram Moolenaar 						      vim_strnsave(p, arg - p);
2661c991144SBram Moolenaar 	    ++names.ga_len;
2671c991144SBram Moolenaar 	    if (*arg == ',')
2681c991144SBram Moolenaar 	    {
2691c991144SBram Moolenaar 		had_comma = TRUE;
2701c991144SBram Moolenaar 		++arg;
2711c991144SBram Moolenaar 	    }
2721c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
2738a7d6542SBram Moolenaar 	    if (*arg == '}')
2741c991144SBram Moolenaar 	    {
2751c991144SBram Moolenaar 		arg = skipwhite_and_linebreak(arg + 1, evalarg);
2761c991144SBram Moolenaar 		break;
2771c991144SBram Moolenaar 	    }
2781c991144SBram Moolenaar 	    if (!had_comma)
2791c991144SBram Moolenaar 	    {
2801c991144SBram Moolenaar 		emsg(_("E1046: Missing comma in import"));
2811c991144SBram Moolenaar 		goto erret;
2821c991144SBram Moolenaar 	    }
2831c991144SBram Moolenaar 	}
2841c991144SBram Moolenaar 	if (names.ga_len == 0)
2851c991144SBram Moolenaar 	{
2861c991144SBram Moolenaar 	    emsg(_(e_import_syntax));
2871c991144SBram Moolenaar 	    goto erret;
2881c991144SBram Moolenaar 	}
2898a7d6542SBram Moolenaar     }
2908a7d6542SBram Moolenaar     else
2918a7d6542SBram Moolenaar     {
2921c991144SBram Moolenaar 	// "import Name from ..."
2931c991144SBram Moolenaar 	// "import * as Name from ..."
2941c991144SBram Moolenaar 	// "import item [as Name] from ..."
2951c991144SBram Moolenaar 	arg = skipwhite_and_linebreak(arg, evalarg);
2961c991144SBram Moolenaar 	if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
2971c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg + 1, evalarg);
298fa29c8abSBram Moolenaar 	else if (eval_isnamec1(*arg))
2998a7d6542SBram Moolenaar 	{
3001c991144SBram Moolenaar 	    char_u  *p = arg;
3011c991144SBram Moolenaar 
302fa29c8abSBram Moolenaar 	    while (eval_isnamec(*arg))
3038a7d6542SBram Moolenaar 		++arg;
3041c991144SBram Moolenaar 	    if (ga_grow(&names, 1) == FAIL)
3051c991144SBram Moolenaar 		goto erret;
3061c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[names.ga_len] =
3071c991144SBram Moolenaar 						      vim_strnsave(p, arg - p);
3081c991144SBram Moolenaar 	    ++names.ga_len;
3091c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
3108a7d6542SBram Moolenaar 	}
3111c991144SBram Moolenaar 	else
3128a7d6542SBram Moolenaar 	{
3131c991144SBram Moolenaar 	    emsg(_(e_import_syntax));
3141c991144SBram Moolenaar 	    goto erret;
3151c991144SBram Moolenaar 	}
3161c991144SBram Moolenaar 
3171c991144SBram Moolenaar 	if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
3181c991144SBram Moolenaar 	{
3191c991144SBram Moolenaar 	    char_u *p;
3201c991144SBram Moolenaar 
3211c991144SBram Moolenaar 	    // skip over "as Name "; no line break allowed after "as"
3228a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 2);
3231c991144SBram Moolenaar 	    p = arg;
324fa29c8abSBram Moolenaar 	    if (eval_isnamec1(*arg))
325fa29c8abSBram Moolenaar 		while (eval_isnamec(*arg))
3268a7d6542SBram Moolenaar 		    ++arg;
327*cbb6bdcdSBram Moolenaar 	    if (check_defined(p, arg - p, cctx) == FAIL)
3281c991144SBram Moolenaar 		goto erret;
3291c991144SBram Moolenaar 	    as_name = vim_strnsave(p, arg - p);
3301c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
3318a7d6542SBram Moolenaar 	}
3328a7d6542SBram Moolenaar 	else if (*arg_start == '*')
3338a7d6542SBram Moolenaar 	{
3348a7d6542SBram Moolenaar 	    emsg(_("E1045: Missing \"as\" after *"));
3351c991144SBram Moolenaar 	    goto erret;
3368a7d6542SBram Moolenaar 	}
3378a7d6542SBram Moolenaar     }
3381c991144SBram Moolenaar 
3391c991144SBram Moolenaar     if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
3408a7d6542SBram Moolenaar     {
341fa29c8abSBram Moolenaar 	emsg(_("E1070: Missing \"from\""));
3421c991144SBram Moolenaar 	goto erret;
3438a7d6542SBram Moolenaar     }
3441c991144SBram Moolenaar 
345962d7213SBram Moolenaar     arg = skipwhite_and_linebreak(arg + 4, evalarg);
3468a7d6542SBram Moolenaar     tv.v_type = VAR_UNKNOWN;
3478a7d6542SBram Moolenaar     // TODO: should we accept any expression?
3488a7d6542SBram Moolenaar     if (*arg == '\'')
3499a78e6dfSBram Moolenaar 	ret = eval_lit_string(&arg, &tv, TRUE);
3508a7d6542SBram Moolenaar     else if (*arg == '"')
3519a78e6dfSBram Moolenaar 	ret = eval_string(&arg, &tv, TRUE);
3528a7d6542SBram Moolenaar     if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
3538a7d6542SBram Moolenaar     {
354fa29c8abSBram Moolenaar 	emsg(_("E1071: Invalid string after \"from\""));
3551c991144SBram Moolenaar 	goto erret;
3568a7d6542SBram Moolenaar     }
3578a7d6542SBram Moolenaar     cmd_end = arg;
3588a7d6542SBram Moolenaar 
3591c991144SBram Moolenaar     /*
3601c991144SBram Moolenaar      * find script file
3611c991144SBram Moolenaar      */
3628a7d6542SBram Moolenaar     if (*tv.vval.v_string == '.')
3638a7d6542SBram Moolenaar     {
3648a7d6542SBram Moolenaar 	size_t		len;
36521b9e977SBram Moolenaar 	scriptitem_T	*si = SCRIPT_ITEM(current_sctx.sc_sid);
3668a7d6542SBram Moolenaar 	char_u		*tail = gettail(si->sn_name);
3678a7d6542SBram Moolenaar 	char_u		*from_name;
3688a7d6542SBram Moolenaar 
3698a7d6542SBram Moolenaar 	// Relative to current script: "./name.vim", "../../name.vim".
3708a7d6542SBram Moolenaar 	len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
3718a7d6542SBram Moolenaar 	from_name = alloc((int)len);
3728a7d6542SBram Moolenaar 	if (from_name == NULL)
3738a7d6542SBram Moolenaar 	{
3748a7d6542SBram Moolenaar 	    clear_tv(&tv);
3751c991144SBram Moolenaar 	    goto erret;
3768a7d6542SBram Moolenaar 	}
3778a7d6542SBram Moolenaar 	vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
3788a7d6542SBram Moolenaar 	add_pathsep(from_name);
3798a7d6542SBram Moolenaar 	STRCAT(from_name, tv.vval.v_string);
3808a7d6542SBram Moolenaar 	simplify_filename(from_name);
3818a7d6542SBram Moolenaar 
3828a7d6542SBram Moolenaar 	res = do_source(from_name, FALSE, DOSO_NONE, &sid);
3838a7d6542SBram Moolenaar 	vim_free(from_name);
3848a7d6542SBram Moolenaar     }
3858a7d6542SBram Moolenaar     else if (mch_isFullName(tv.vval.v_string))
3868a7d6542SBram Moolenaar     {
3878a7d6542SBram Moolenaar 	// Absolute path: "/tmp/name.vim"
3888a7d6542SBram Moolenaar 	res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
3898a7d6542SBram Moolenaar     }
3908a7d6542SBram Moolenaar     else
3918a7d6542SBram Moolenaar     {
3928a7d6542SBram Moolenaar 	size_t	    len = 7 + STRLEN(tv.vval.v_string) + 1;
3938a7d6542SBram Moolenaar 	char_u	    *from_name;
3948a7d6542SBram Moolenaar 
3958a7d6542SBram Moolenaar 	// Find file in "import" subdirs in 'runtimepath'.
3968a7d6542SBram Moolenaar 	from_name = alloc((int)len);
3978a7d6542SBram Moolenaar 	if (from_name == NULL)
3988a7d6542SBram Moolenaar 	{
3998a7d6542SBram Moolenaar 	    clear_tv(&tv);
4001c991144SBram Moolenaar 	    goto erret;
4018a7d6542SBram Moolenaar 	}
4028a7d6542SBram Moolenaar 	vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
4038a7d6542SBram Moolenaar 	res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
4048a7d6542SBram Moolenaar 	vim_free(from_name);
4058a7d6542SBram Moolenaar     }
4068a7d6542SBram Moolenaar 
4078a7d6542SBram Moolenaar     if (res == FAIL || sid <= 0)
4088a7d6542SBram Moolenaar     {
4098a7d6542SBram Moolenaar 	semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
4108a7d6542SBram Moolenaar 	clear_tv(&tv);
4111c991144SBram Moolenaar 	goto erret;
4128a7d6542SBram Moolenaar     }
4138a7d6542SBram Moolenaar     clear_tv(&tv);
4148a7d6542SBram Moolenaar 
4158a7d6542SBram Moolenaar     if (*arg_start == '*')
4168a7d6542SBram Moolenaar     {
4178a7d6542SBram Moolenaar 	imported_T *imported = new_imported(gap != NULL ? gap
41821b9e977SBram Moolenaar 					: &SCRIPT_ITEM(import_sid)->sn_imports);
4198a7d6542SBram Moolenaar 
4208a7d6542SBram Moolenaar 	if (imported == NULL)
4211c991144SBram Moolenaar 	    goto erret;
4221c991144SBram Moolenaar 	imported->imp_name = as_name;
4231c991144SBram Moolenaar 	as_name = NULL;
4248a7d6542SBram Moolenaar 	imported->imp_sid = sid;
4258a7d6542SBram Moolenaar 	imported->imp_all = TRUE;
4268a7d6542SBram Moolenaar     }
4278a7d6542SBram Moolenaar     else
4288a7d6542SBram Moolenaar     {
4291c991144SBram Moolenaar 	int i;
4301c991144SBram Moolenaar 
4318a7d6542SBram Moolenaar 	arg = arg_start;
4328a7d6542SBram Moolenaar 	if (*arg == '{')
4338a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
4341c991144SBram Moolenaar 	for (i = 0; i < names.ga_len; ++i)
4358a7d6542SBram Moolenaar 	{
4361c991144SBram Moolenaar 	    char_u	*name = ((char_u **)names.ga_data)[i];
4378a7d6542SBram Moolenaar 	    int		idx;
4388a7d6542SBram Moolenaar 	    imported_T	*imported;
439f2d5c240SBram Moolenaar 	    ufunc_T	*ufunc = NULL;
440f2d5c240SBram Moolenaar 	    type_T	*type;
4418a7d6542SBram Moolenaar 
4421c991144SBram Moolenaar 	    idx = find_exported(sid, name, &ufunc, &type);
4438a7d6542SBram Moolenaar 
444f2d5c240SBram Moolenaar 	    if (idx < 0 && ufunc == NULL)
4451c991144SBram Moolenaar 		goto erret;
4468a7d6542SBram Moolenaar 
4471c991144SBram Moolenaar 	    if (check_defined(name, STRLEN(name), cctx) == FAIL)
4481c991144SBram Moolenaar 		goto erret;
4495269bd2aSBram Moolenaar 
4508a7d6542SBram Moolenaar 	    imported = new_imported(gap != NULL ? gap
45121b9e977SBram Moolenaar 				       : &SCRIPT_ITEM(import_sid)->sn_imports);
4528a7d6542SBram Moolenaar 	    if (imported == NULL)
4531c991144SBram Moolenaar 		goto erret;
4548a7d6542SBram Moolenaar 
4558a7d6542SBram Moolenaar 	    // TODO: check for "as" following
4561c991144SBram Moolenaar 	    // imported->imp_name = vim_strsave(as_name);
4571c991144SBram Moolenaar 	    imported->imp_name = name;
4581c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[i] = NULL;
4598a7d6542SBram Moolenaar 	    imported->imp_sid = sid;
4608a7d6542SBram Moolenaar 	    if (idx >= 0)
4618a7d6542SBram Moolenaar 	    {
462f2d5c240SBram Moolenaar 		imported->imp_type = type;
4638a7d6542SBram Moolenaar 		imported->imp_var_vals_idx = idx;
4648a7d6542SBram Moolenaar 	    }
4658a7d6542SBram Moolenaar 	    else
4668a7d6542SBram Moolenaar 		imported->imp_funcname = ufunc->uf_name;
4678a7d6542SBram Moolenaar 	}
4688a7d6542SBram Moolenaar     }
4691c991144SBram Moolenaar erret:
4701c991144SBram Moolenaar     ga_clear_strings(&names);
4711c991144SBram Moolenaar     vim_free(as_name);
4728a7d6542SBram Moolenaar     return cmd_end;
4738a7d6542SBram Moolenaar }
4748a7d6542SBram Moolenaar 
475c82a5b5dSBram Moolenaar /*
476c82a5b5dSBram Moolenaar  * Declare a script-local variable without init: "let var: type".
477c82a5b5dSBram Moolenaar  * "const" is an error since the value is missing.
478c82a5b5dSBram Moolenaar  * Returns a pointer to after the type.
479c82a5b5dSBram Moolenaar  */
480c82a5b5dSBram Moolenaar     char_u *
481c82a5b5dSBram Moolenaar vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
482c82a5b5dSBram Moolenaar {
483c82a5b5dSBram Moolenaar     char_u	    *p;
484c82a5b5dSBram Moolenaar     char_u	    *name;
485c82a5b5dSBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
486c82a5b5dSBram Moolenaar     type_T	    *type;
487c82a5b5dSBram Moolenaar     int		    called_emsg_before = called_emsg;
488c82a5b5dSBram Moolenaar     typval_T	    init_tv;
489c82a5b5dSBram Moolenaar 
490c82a5b5dSBram Moolenaar     if (eap->cmdidx == CMD_const)
491c82a5b5dSBram Moolenaar     {
492c82a5b5dSBram Moolenaar 	emsg(_(e_const_req_value));
493c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
494c82a5b5dSBram Moolenaar     }
495c82a5b5dSBram Moolenaar 
496c82a5b5dSBram Moolenaar     // Check for valid starting character.
497c82a5b5dSBram Moolenaar     if (!eval_isnamec1(*arg))
498c82a5b5dSBram Moolenaar     {
499c82a5b5dSBram Moolenaar 	semsg(_(e_invarg2), arg);
500c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
501c82a5b5dSBram Moolenaar     }
502c82a5b5dSBram Moolenaar 
503984dddbeSBram Moolenaar     for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
5043b74b6b4SBram Moolenaar 	if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
505984dddbeSBram Moolenaar 	    break;
506c82a5b5dSBram Moolenaar 
507c82a5b5dSBram Moolenaar     if (*p != ':')
508c82a5b5dSBram Moolenaar     {
509c82a5b5dSBram Moolenaar 	emsg(_(e_type_req));
510c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
511c82a5b5dSBram Moolenaar     }
512984dddbeSBram Moolenaar     if (!VIM_ISWHITE(p[1]))
513984dddbeSBram Moolenaar     {
514984dddbeSBram Moolenaar 	semsg(_(e_white_after), ":");
515984dddbeSBram Moolenaar 	return arg + STRLEN(arg);
516984dddbeSBram Moolenaar     }
517c82a5b5dSBram Moolenaar     name = vim_strnsave(arg, p - arg);
518c82a5b5dSBram Moolenaar 
519c82a5b5dSBram Moolenaar     // parse type
520c82a5b5dSBram Moolenaar     p = skipwhite(p + 1);
521c82a5b5dSBram Moolenaar     type = parse_type(&p, &si->sn_type_list);
522c82a5b5dSBram Moolenaar     if (called_emsg != called_emsg_before)
523f3decc58SBram Moolenaar     {
524f3decc58SBram Moolenaar 	vim_free(name);
525c82a5b5dSBram Moolenaar 	return p;
526f3decc58SBram Moolenaar     }
527c82a5b5dSBram Moolenaar 
528c82a5b5dSBram Moolenaar     // Create the variable with 0/NULL value.
529c82a5b5dSBram Moolenaar     CLEAR_FIELD(init_tv);
530c82a5b5dSBram Moolenaar     init_tv.v_type = type->tt_type;
531c82a5b5dSBram Moolenaar     set_var_const(name, type, &init_tv, FALSE, 0);
532c82a5b5dSBram Moolenaar 
533c82a5b5dSBram Moolenaar     vim_free(name);
534c82a5b5dSBram Moolenaar     return p;
535c82a5b5dSBram Moolenaar }
536c82a5b5dSBram Moolenaar 
53734db91f7SBram Moolenaar /*
53834db91f7SBram Moolenaar  * Check if the type of script variable "dest" allows assigning "value".
53934db91f7SBram Moolenaar  */
540c785b9a7SBram Moolenaar     int
54134db91f7SBram Moolenaar check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
54234db91f7SBram Moolenaar {
54334db91f7SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
54434db91f7SBram Moolenaar     int		    idx;
54534db91f7SBram Moolenaar 
54634db91f7SBram Moolenaar     // Find the svar_T in sn_var_vals.
54734db91f7SBram Moolenaar     for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
54834db91f7SBram Moolenaar     {
54934db91f7SBram Moolenaar 	svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
55034db91f7SBram Moolenaar 
55134db91f7SBram Moolenaar 	if (sv->sv_tv == dest)
55234db91f7SBram Moolenaar 	{
55334db91f7SBram Moolenaar 	    if (sv->sv_const)
554c785b9a7SBram Moolenaar 	    {
55534db91f7SBram Moolenaar 		semsg(_(e_readonlyvar), name);
556c785b9a7SBram Moolenaar 		return FAIL;
557c785b9a7SBram Moolenaar 	    }
558c785b9a7SBram Moolenaar 	    return check_type(sv->sv_type, typval2type(value), TRUE);
55934db91f7SBram Moolenaar 	}
56034db91f7SBram Moolenaar     }
56134db91f7SBram Moolenaar     iemsg("check_script_var_type(): not found");
562c785b9a7SBram Moolenaar     return OK; // not really
56334db91f7SBram Moolenaar }
564c82a5b5dSBram Moolenaar 
5658a7d6542SBram Moolenaar #endif // FEAT_EVAL
566