xref: /vim-8.2.3635/src/vim9script.c (revision 7cb6fc29)
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 
208a7d6542SBram Moolenaar     int
218a7d6542SBram Moolenaar in_vim9script(void)
228a7d6542SBram Moolenaar {
23eb6880b6SBram Moolenaar     // Do not go up the stack, a ":function" inside vim9script uses legacy
24eb6880b6SBram Moolenaar     // syntax.  "sc_version" is also set when compiling a ":def" function in
25eb6880b6SBram Moolenaar     // legacy script.
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     {
39451c2e35SBram Moolenaar 	emsg(_(e_vim9script_can_only_be_used_in_script));
408a7d6542SBram Moolenaar 	return;
418a7d6542SBram Moolenaar     }
42101f4810SBram Moolenaar     si = SCRIPT_ITEM(current_sctx.sc_sid);
438a7d6542SBram Moolenaar     if (si->sn_had_command)
448a7d6542SBram Moolenaar     {
45451c2e35SBram Moolenaar 	emsg(_(e_vim9script_must_be_first_command_in_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 /*
60ae616494SBram Moolenaar  * When in Vim9 script give an error and return FAIL.
61ae616494SBram Moolenaar  */
62ae616494SBram Moolenaar     int
63ae616494SBram Moolenaar not_in_vim9(exarg_T *eap)
64ae616494SBram Moolenaar {
6568e30449SBram Moolenaar     if (in_vim9script())
66ae616494SBram Moolenaar 	switch (eap->cmdidx)
67ae616494SBram Moolenaar 	{
68ae616494SBram Moolenaar 	    case CMD_append:
69ae616494SBram Moolenaar 	    case CMD_change:
70f5a48010SBram Moolenaar 	    case CMD_insert:
71f5a48010SBram Moolenaar 	    case CMD_t:
72ae616494SBram Moolenaar 	    case CMD_xit:
73451c2e35SBram Moolenaar 		semsg(_(e_missing_let_str), eap->cmd);
74ae616494SBram Moolenaar 		return FAIL;
75ae616494SBram Moolenaar 	    default: break;
76ae616494SBram Moolenaar 	}
77ae616494SBram Moolenaar     return OK;
78ae616494SBram Moolenaar }
79ae616494SBram Moolenaar 
80ae616494SBram Moolenaar /*
818a7d6542SBram Moolenaar  * ":export let Name: type"
828a7d6542SBram Moolenaar  * ":export const Name: type"
838a7d6542SBram Moolenaar  * ":export def Name(..."
848a7d6542SBram Moolenaar  * ":export class Name ..."
858a7d6542SBram Moolenaar  */
868a7d6542SBram Moolenaar     void
8709689a02SBram Moolenaar ex_export(exarg_T *eap)
888a7d6542SBram Moolenaar {
89eb6880b6SBram Moolenaar     if (!in_vim9script())
908a7d6542SBram Moolenaar     {
91451c2e35SBram Moolenaar 	emsg(_(e_export_can_only_be_used_in_vim9script));
928a7d6542SBram Moolenaar 	return;
938a7d6542SBram Moolenaar     }
948a7d6542SBram Moolenaar 
958a7d6542SBram Moolenaar     eap->cmd = eap->arg;
968a7d6542SBram Moolenaar     (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
978a7d6542SBram Moolenaar     switch (eap->cmdidx)
988a7d6542SBram Moolenaar     {
998a7d6542SBram Moolenaar 	case CMD_let:
1008a7d6542SBram Moolenaar 	case CMD_const:
1018a7d6542SBram Moolenaar 	case CMD_def:
1028a7d6542SBram Moolenaar 	// case CMD_class:
1038a7d6542SBram Moolenaar 	    is_export = TRUE;
1048a7d6542SBram Moolenaar 	    do_cmdline(eap->cmd, eap->getline, eap->cookie,
1058a7d6542SBram Moolenaar 						DOCMD_VERBOSE + DOCMD_NOWAIT);
1068a7d6542SBram Moolenaar 
1078a7d6542SBram Moolenaar 	    // The command will reset "is_export" when exporting an item.
1088a7d6542SBram Moolenaar 	    if (is_export)
1098a7d6542SBram Moolenaar 	    {
110451c2e35SBram Moolenaar 		emsg(_(e_export_with_invalid_argument));
1118a7d6542SBram Moolenaar 		is_export = FALSE;
1128a7d6542SBram Moolenaar 	    }
1138a7d6542SBram Moolenaar 	    break;
1148a7d6542SBram Moolenaar 	default:
115451c2e35SBram Moolenaar 	    emsg(_(e_invalid_command_after_export));
1168a7d6542SBram Moolenaar 	    break;
1178a7d6542SBram Moolenaar     }
1188a7d6542SBram Moolenaar }
1198a7d6542SBram Moolenaar 
1208a7d6542SBram Moolenaar /*
1218a7d6542SBram Moolenaar  * Add a new imported item entry to the current script.
1228a7d6542SBram Moolenaar  */
1238a7d6542SBram Moolenaar     static imported_T *
1248a7d6542SBram Moolenaar new_imported(garray_T *gap)
1258a7d6542SBram Moolenaar {
1268a7d6542SBram Moolenaar     if (ga_grow(gap, 1) == OK)
1278a7d6542SBram Moolenaar 	return ((imported_T *)gap->ga_data + gap->ga_len++);
1288a7d6542SBram Moolenaar     return NULL;
1298a7d6542SBram Moolenaar }
1308a7d6542SBram Moolenaar 
1318a7d6542SBram Moolenaar /*
1328a7d6542SBram Moolenaar  * Free all imported items in script "sid".
1338a7d6542SBram Moolenaar  */
1348a7d6542SBram Moolenaar     void
1358a7d6542SBram Moolenaar free_imports(int sid)
1368a7d6542SBram Moolenaar {
13721b9e977SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(sid);
1388a7d6542SBram Moolenaar     int		    idx;
1398a7d6542SBram Moolenaar 
1408a7d6542SBram Moolenaar     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
1418a7d6542SBram Moolenaar     {
14220431c9dSBram Moolenaar 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
1438a7d6542SBram Moolenaar 
1448a7d6542SBram Moolenaar 	vim_free(imp->imp_name);
1458a7d6542SBram Moolenaar     }
1468a7d6542SBram Moolenaar     ga_clear(&si->sn_imports);
14720431c9dSBram Moolenaar     ga_clear(&si->sn_var_vals);
1486110e79aSBram Moolenaar     clear_type_list(&si->sn_type_list);
1498a7d6542SBram Moolenaar }
1508a7d6542SBram Moolenaar 
1518a7d6542SBram Moolenaar /*
1528a7d6542SBram Moolenaar  * ":import Item from 'filename'"
1538a7d6542SBram Moolenaar  * ":import Item as Alias from 'filename'"
1548a7d6542SBram Moolenaar  * ":import {Item} from 'filename'".
1558a7d6542SBram Moolenaar  * ":import {Item as Alias} from 'filename'"
1568a7d6542SBram Moolenaar  * ":import {Item, Item} from 'filename'"
1578a7d6542SBram Moolenaar  * ":import {Item, Item as Alias} from 'filename'"
1588a7d6542SBram Moolenaar  *
1598a7d6542SBram Moolenaar  * ":import * as Name from 'filename'"
1608a7d6542SBram Moolenaar  */
1618a7d6542SBram Moolenaar     void
1628a7d6542SBram Moolenaar ex_import(exarg_T *eap)
1638a7d6542SBram Moolenaar {
164101f4810SBram Moolenaar     char_u	*cmd_end;
1651c991144SBram Moolenaar     evalarg_T	evalarg;
1668a7d6542SBram Moolenaar 
167101f4810SBram Moolenaar     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
168101f4810SBram Moolenaar     {
169451c2e35SBram Moolenaar 	emsg(_(e_import_can_only_be_used_in_script));
170101f4810SBram Moolenaar 	return;
171101f4810SBram Moolenaar     }
1721c991144SBram Moolenaar     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
173101f4810SBram Moolenaar 
1741c991144SBram Moolenaar     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
1751c991144SBram Moolenaar 							       &evalarg, NULL);
1768a7d6542SBram Moolenaar     if (cmd_end != NULL)
1778a7d6542SBram Moolenaar 	eap->nextcmd = check_nextcmd(cmd_end);
1781c991144SBram Moolenaar     clear_evalarg(&evalarg, eap);
1798a7d6542SBram Moolenaar }
1808a7d6542SBram Moolenaar 
1818a7d6542SBram Moolenaar /*
182f2d5c240SBram Moolenaar  * Find an exported item in "sid" matching the name at "*argp".
183f2d5c240SBram Moolenaar  * When it is a variable return the index.
184f2d5c240SBram Moolenaar  * When it is a user function return "*ufunc".
185f2d5c240SBram Moolenaar  * When not found returns -1 and "*ufunc" is NULL.
186f2d5c240SBram Moolenaar  */
187f2d5c240SBram Moolenaar     int
188f2d5c240SBram Moolenaar find_exported(
189f2d5c240SBram Moolenaar 	int	    sid,
1901c991144SBram Moolenaar 	char_u	    *name,
191f2d5c240SBram Moolenaar 	ufunc_T	    **ufunc,
192f2d5c240SBram Moolenaar 	type_T	    **type)
193f2d5c240SBram Moolenaar {
194f2d5c240SBram Moolenaar     int		idx = -1;
195f2d5c240SBram Moolenaar     svar_T	*sv;
196f2d5c240SBram Moolenaar     scriptitem_T *script = SCRIPT_ITEM(sid);
197f2d5c240SBram Moolenaar 
198f2d5c240SBram Moolenaar     // find name in "script"
199f2d5c240SBram Moolenaar     // TODO: also find script-local user function
200f2d5c240SBram Moolenaar     idx = get_script_item_idx(sid, name, FALSE);
201f2d5c240SBram Moolenaar     if (idx >= 0)
202f2d5c240SBram Moolenaar     {
203f2d5c240SBram Moolenaar 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
204f2d5c240SBram Moolenaar 	if (!sv->sv_export)
205f2d5c240SBram Moolenaar 	{
206451c2e35SBram Moolenaar 	    semsg(_(e_item_not_exported_in_script_str), name);
207f2d5c240SBram Moolenaar 	    return -1;
208f2d5c240SBram Moolenaar 	}
209f2d5c240SBram Moolenaar 	*type = sv->sv_type;
210f2d5c240SBram Moolenaar 	*ufunc = NULL;
211f2d5c240SBram Moolenaar     }
212f2d5c240SBram Moolenaar     else
213f2d5c240SBram Moolenaar     {
214f2d5c240SBram Moolenaar 	char_u	buffer[200];
215f2d5c240SBram Moolenaar 	char_u	*funcname;
216f2d5c240SBram Moolenaar 
217f2d5c240SBram Moolenaar 	// it could be a user function.
2185a67c37aSBram Moolenaar 	if (STRLEN(name) < sizeof(buffer) - 15)
219f2d5c240SBram Moolenaar 	    funcname = buffer;
220f2d5c240SBram Moolenaar 	else
221f2d5c240SBram Moolenaar 	{
2225a67c37aSBram Moolenaar 	    funcname = alloc(STRLEN(name) + 15);
223f2d5c240SBram Moolenaar 	    if (funcname == NULL)
224f2d5c240SBram Moolenaar 		return -1;
225f2d5c240SBram Moolenaar 	}
226f2d5c240SBram Moolenaar 	funcname[0] = K_SPECIAL;
227f2d5c240SBram Moolenaar 	funcname[1] = KS_EXTRA;
228f2d5c240SBram Moolenaar 	funcname[2] = (int)KE_SNR;
229f2d5c240SBram Moolenaar 	sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
2304c17ad94SBram Moolenaar 	*ufunc = find_func(funcname, FALSE, NULL);
231f2d5c240SBram Moolenaar 	if (funcname != buffer)
232f2d5c240SBram Moolenaar 	    vim_free(funcname);
233f2d5c240SBram Moolenaar 
234f2d5c240SBram Moolenaar 	if (*ufunc == NULL)
235f2d5c240SBram Moolenaar 	{
236451c2e35SBram Moolenaar 	    semsg(_(e_item_not_found_in_script_str), name);
237f2d5c240SBram Moolenaar 	    return -1;
238f2d5c240SBram Moolenaar 	}
239f2d5c240SBram Moolenaar     }
240f2d5c240SBram Moolenaar 
241f2d5c240SBram Moolenaar     return idx;
242f2d5c240SBram Moolenaar }
243f2d5c240SBram Moolenaar 
244f2d5c240SBram Moolenaar /*
2458a7d6542SBram Moolenaar  * Handle an ":import" command and add the resulting imported_T to "gap", when
2468a7d6542SBram Moolenaar  * not NULL, or script "import_sid" sn_imports.
2478a7d6542SBram Moolenaar  * Returns a pointer to after the command or NULL in case of failure
2488a7d6542SBram Moolenaar  */
2498a7d6542SBram Moolenaar     char_u *
2501c991144SBram Moolenaar handle_import(
2511c991144SBram Moolenaar 	char_u	    *arg_start,
2521c991144SBram Moolenaar 	garray_T    *gap,
2531c991144SBram Moolenaar 	int	    import_sid,
2541c991144SBram Moolenaar 	evalarg_T   *evalarg,
2551c991144SBram Moolenaar 	void	    *cctx)
2568a7d6542SBram Moolenaar {
2578a7d6542SBram Moolenaar     char_u	*arg = arg_start;
2581c991144SBram Moolenaar     char_u	*cmd_end = NULL;
2591c991144SBram Moolenaar     char_u	*as_name = NULL;
2608a7d6542SBram Moolenaar     int		ret = FAIL;
2618a7d6542SBram Moolenaar     typval_T	tv;
2628a7d6542SBram Moolenaar     int		sid = -1;
2638a7d6542SBram Moolenaar     int		res;
2641c991144SBram Moolenaar     garray_T	names;
2658a7d6542SBram Moolenaar 
2661c991144SBram Moolenaar     ga_init2(&names, sizeof(char_u *), 10);
2678a7d6542SBram Moolenaar     if (*arg == '{')
2688a7d6542SBram Moolenaar     {
2691c991144SBram Moolenaar 	// "import {item, item} from ..."
2701c991144SBram Moolenaar 	arg = skipwhite_and_linebreak(arg + 1, evalarg);
2711c991144SBram Moolenaar 	for (;;)
2721c991144SBram Moolenaar 	{
2731c991144SBram Moolenaar 	    char_u  *p = arg;
2741c991144SBram Moolenaar 	    int	    had_comma = FALSE;
2751c991144SBram Moolenaar 
2761c991144SBram Moolenaar 	    while (eval_isnamec(*arg))
2778a7d6542SBram Moolenaar 		++arg;
2781c991144SBram Moolenaar 	    if (p == arg)
2791c991144SBram Moolenaar 		break;
2801c991144SBram Moolenaar 	    if (ga_grow(&names, 1) == FAIL)
2811c991144SBram Moolenaar 		goto erret;
2821c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[names.ga_len] =
2831c991144SBram Moolenaar 						      vim_strnsave(p, arg - p);
2841c991144SBram Moolenaar 	    ++names.ga_len;
2851c991144SBram Moolenaar 	    if (*arg == ',')
2861c991144SBram Moolenaar 	    {
2871c991144SBram Moolenaar 		had_comma = TRUE;
2881c991144SBram Moolenaar 		++arg;
2891c991144SBram Moolenaar 	    }
2901c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
2918a7d6542SBram Moolenaar 	    if (*arg == '}')
2921c991144SBram Moolenaar 	    {
2931c991144SBram Moolenaar 		arg = skipwhite_and_linebreak(arg + 1, evalarg);
2941c991144SBram Moolenaar 		break;
2951c991144SBram Moolenaar 	    }
2961c991144SBram Moolenaar 	    if (!had_comma)
2971c991144SBram Moolenaar 	    {
298451c2e35SBram Moolenaar 		emsg(_(e_missing_comma_in_import));
2991c991144SBram Moolenaar 		goto erret;
3001c991144SBram Moolenaar 	    }
3011c991144SBram Moolenaar 	}
3021c991144SBram Moolenaar 	if (names.ga_len == 0)
3031c991144SBram Moolenaar 	{
304451c2e35SBram Moolenaar 	    emsg(_(e_syntax_error_in_import));
3051c991144SBram Moolenaar 	    goto erret;
3061c991144SBram Moolenaar 	}
3078a7d6542SBram Moolenaar     }
3088a7d6542SBram Moolenaar     else
3098a7d6542SBram Moolenaar     {
3101c991144SBram Moolenaar 	// "import Name from ..."
3111c991144SBram Moolenaar 	// "import * as Name from ..."
3121c991144SBram Moolenaar 	// "import item [as Name] from ..."
3131c991144SBram Moolenaar 	arg = skipwhite_and_linebreak(arg, evalarg);
3141c991144SBram Moolenaar 	if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
3151c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg + 1, evalarg);
316fa29c8abSBram Moolenaar 	else if (eval_isnamec1(*arg))
3178a7d6542SBram Moolenaar 	{
3181c991144SBram Moolenaar 	    char_u  *p = arg;
3191c991144SBram Moolenaar 
320fa29c8abSBram Moolenaar 	    while (eval_isnamec(*arg))
3218a7d6542SBram Moolenaar 		++arg;
3221c991144SBram Moolenaar 	    if (ga_grow(&names, 1) == FAIL)
3231c991144SBram Moolenaar 		goto erret;
3241c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[names.ga_len] =
3251c991144SBram Moolenaar 						      vim_strnsave(p, arg - p);
3261c991144SBram Moolenaar 	    ++names.ga_len;
3271c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
3288a7d6542SBram Moolenaar 	}
3291c991144SBram Moolenaar 	else
3308a7d6542SBram Moolenaar 	{
331451c2e35SBram Moolenaar 	    emsg(_(e_syntax_error_in_import));
3321c991144SBram Moolenaar 	    goto erret;
3331c991144SBram Moolenaar 	}
3341c991144SBram Moolenaar 
3351c991144SBram Moolenaar 	if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
3361c991144SBram Moolenaar 	{
3371c991144SBram Moolenaar 	    char_u *p;
3381c991144SBram Moolenaar 
3391c991144SBram Moolenaar 	    // skip over "as Name "; no line break allowed after "as"
3408a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 2);
3411c991144SBram Moolenaar 	    p = arg;
342fa29c8abSBram Moolenaar 	    if (eval_isnamec1(*arg))
343fa29c8abSBram Moolenaar 		while (eval_isnamec(*arg))
3448a7d6542SBram Moolenaar 		    ++arg;
345cbb6bdcdSBram Moolenaar 	    if (check_defined(p, arg - p, cctx) == FAIL)
3461c991144SBram Moolenaar 		goto erret;
3471c991144SBram Moolenaar 	    as_name = vim_strnsave(p, arg - p);
3481c991144SBram Moolenaar 	    arg = skipwhite_and_linebreak(arg, evalarg);
3498a7d6542SBram Moolenaar 	}
3508a7d6542SBram Moolenaar 	else if (*arg_start == '*')
3518a7d6542SBram Moolenaar 	{
352451c2e35SBram Moolenaar 	    emsg(_(e_missing_as_after_star));
3531c991144SBram Moolenaar 	    goto erret;
3548a7d6542SBram Moolenaar 	}
3558a7d6542SBram Moolenaar     }
3561c991144SBram Moolenaar 
3571c991144SBram Moolenaar     if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
3588a7d6542SBram Moolenaar     {
359451c2e35SBram Moolenaar 	emsg(_(e_missing_from));
3601c991144SBram Moolenaar 	goto erret;
3618a7d6542SBram Moolenaar     }
3621c991144SBram Moolenaar 
363962d7213SBram Moolenaar     arg = skipwhite_and_linebreak(arg + 4, evalarg);
3648a7d6542SBram Moolenaar     tv.v_type = VAR_UNKNOWN;
3658a7d6542SBram Moolenaar     // TODO: should we accept any expression?
3668a7d6542SBram Moolenaar     if (*arg == '\'')
3679a78e6dfSBram Moolenaar 	ret = eval_lit_string(&arg, &tv, TRUE);
3688a7d6542SBram Moolenaar     else if (*arg == '"')
3699a78e6dfSBram Moolenaar 	ret = eval_string(&arg, &tv, TRUE);
3708a7d6542SBram Moolenaar     if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
3718a7d6542SBram Moolenaar     {
372451c2e35SBram Moolenaar 	emsg(_(e_invalid_string_after_from));
3731c991144SBram Moolenaar 	goto erret;
3748a7d6542SBram Moolenaar     }
3758a7d6542SBram Moolenaar     cmd_end = arg;
3768a7d6542SBram Moolenaar 
3771c991144SBram Moolenaar     /*
3781c991144SBram Moolenaar      * find script file
3791c991144SBram Moolenaar      */
3808a7d6542SBram Moolenaar     if (*tv.vval.v_string == '.')
3818a7d6542SBram Moolenaar     {
3828a7d6542SBram Moolenaar 	size_t		len;
38321b9e977SBram Moolenaar 	scriptitem_T	*si = SCRIPT_ITEM(current_sctx.sc_sid);
3848a7d6542SBram Moolenaar 	char_u		*tail = gettail(si->sn_name);
3858a7d6542SBram Moolenaar 	char_u		*from_name;
3868a7d6542SBram Moolenaar 
3878a7d6542SBram Moolenaar 	// Relative to current script: "./name.vim", "../../name.vim".
3888a7d6542SBram Moolenaar 	len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
3898a7d6542SBram Moolenaar 	from_name = alloc((int)len);
3908a7d6542SBram Moolenaar 	if (from_name == NULL)
3918a7d6542SBram Moolenaar 	{
3928a7d6542SBram Moolenaar 	    clear_tv(&tv);
3931c991144SBram Moolenaar 	    goto erret;
3948a7d6542SBram Moolenaar 	}
3958a7d6542SBram Moolenaar 	vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
3968a7d6542SBram Moolenaar 	add_pathsep(from_name);
3978a7d6542SBram Moolenaar 	STRCAT(from_name, tv.vval.v_string);
3988a7d6542SBram Moolenaar 	simplify_filename(from_name);
3998a7d6542SBram Moolenaar 
4008a7d6542SBram Moolenaar 	res = do_source(from_name, FALSE, DOSO_NONE, &sid);
4018a7d6542SBram Moolenaar 	vim_free(from_name);
4028a7d6542SBram Moolenaar     }
4038a7d6542SBram Moolenaar     else if (mch_isFullName(tv.vval.v_string))
4048a7d6542SBram Moolenaar     {
4058a7d6542SBram Moolenaar 	// Absolute path: "/tmp/name.vim"
4068a7d6542SBram Moolenaar 	res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
4078a7d6542SBram Moolenaar     }
4088a7d6542SBram Moolenaar     else
4098a7d6542SBram Moolenaar     {
4108a7d6542SBram Moolenaar 	size_t	    len = 7 + STRLEN(tv.vval.v_string) + 1;
4118a7d6542SBram Moolenaar 	char_u	    *from_name;
4128a7d6542SBram Moolenaar 
4138a7d6542SBram Moolenaar 	// Find file in "import" subdirs in 'runtimepath'.
4148a7d6542SBram Moolenaar 	from_name = alloc((int)len);
4158a7d6542SBram Moolenaar 	if (from_name == NULL)
4168a7d6542SBram Moolenaar 	{
4178a7d6542SBram Moolenaar 	    clear_tv(&tv);
4181c991144SBram Moolenaar 	    goto erret;
4198a7d6542SBram Moolenaar 	}
4208a7d6542SBram Moolenaar 	vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
4218a7d6542SBram Moolenaar 	res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
4228a7d6542SBram Moolenaar 	vim_free(from_name);
4238a7d6542SBram Moolenaar     }
4248a7d6542SBram Moolenaar 
4258a7d6542SBram Moolenaar     if (res == FAIL || sid <= 0)
4268a7d6542SBram Moolenaar     {
427451c2e35SBram Moolenaar 	semsg(_(e_could_not_import_str), tv.vval.v_string);
4288a7d6542SBram Moolenaar 	clear_tv(&tv);
4291c991144SBram Moolenaar 	goto erret;
4308a7d6542SBram Moolenaar     }
4318a7d6542SBram Moolenaar     clear_tv(&tv);
4328a7d6542SBram Moolenaar 
4338a7d6542SBram Moolenaar     if (*arg_start == '*')
4348a7d6542SBram Moolenaar     {
4358a7d6542SBram Moolenaar 	imported_T *imported = new_imported(gap != NULL ? gap
43621b9e977SBram Moolenaar 					: &SCRIPT_ITEM(import_sid)->sn_imports);
4378a7d6542SBram Moolenaar 
4388a7d6542SBram Moolenaar 	if (imported == NULL)
4391c991144SBram Moolenaar 	    goto erret;
4401c991144SBram Moolenaar 	imported->imp_name = as_name;
4411c991144SBram Moolenaar 	as_name = NULL;
4428a7d6542SBram Moolenaar 	imported->imp_sid = sid;
4438a7d6542SBram Moolenaar 	imported->imp_all = TRUE;
4448a7d6542SBram Moolenaar     }
4458a7d6542SBram Moolenaar     else
4468a7d6542SBram Moolenaar     {
4471c991144SBram Moolenaar 	int i;
4481c991144SBram Moolenaar 
4498a7d6542SBram Moolenaar 	arg = arg_start;
4508a7d6542SBram Moolenaar 	if (*arg == '{')
4518a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
4521c991144SBram Moolenaar 	for (i = 0; i < names.ga_len; ++i)
4538a7d6542SBram Moolenaar 	{
4541c991144SBram Moolenaar 	    char_u	*name = ((char_u **)names.ga_data)[i];
4558a7d6542SBram Moolenaar 	    int		idx;
4568a7d6542SBram Moolenaar 	    imported_T	*imported;
457f2d5c240SBram Moolenaar 	    ufunc_T	*ufunc = NULL;
458f2d5c240SBram Moolenaar 	    type_T	*type;
4598a7d6542SBram Moolenaar 
4601c991144SBram Moolenaar 	    idx = find_exported(sid, name, &ufunc, &type);
4618a7d6542SBram Moolenaar 
462f2d5c240SBram Moolenaar 	    if (idx < 0 && ufunc == NULL)
4631c991144SBram Moolenaar 		goto erret;
4648a7d6542SBram Moolenaar 
4651c991144SBram Moolenaar 	    if (check_defined(name, STRLEN(name), cctx) == FAIL)
4661c991144SBram Moolenaar 		goto erret;
4675269bd2aSBram Moolenaar 
4688a7d6542SBram Moolenaar 	    imported = new_imported(gap != NULL ? gap
46921b9e977SBram Moolenaar 				       : &SCRIPT_ITEM(import_sid)->sn_imports);
4708a7d6542SBram Moolenaar 	    if (imported == NULL)
4711c991144SBram Moolenaar 		goto erret;
4728a7d6542SBram Moolenaar 
4738a7d6542SBram Moolenaar 	    // TODO: check for "as" following
4741c991144SBram Moolenaar 	    // imported->imp_name = vim_strsave(as_name);
4751c991144SBram Moolenaar 	    imported->imp_name = name;
4761c991144SBram Moolenaar 	    ((char_u **)names.ga_data)[i] = NULL;
4778a7d6542SBram Moolenaar 	    imported->imp_sid = sid;
4788a7d6542SBram Moolenaar 	    if (idx >= 0)
4798a7d6542SBram Moolenaar 	    {
480f2d5c240SBram Moolenaar 		imported->imp_type = type;
4818a7d6542SBram Moolenaar 		imported->imp_var_vals_idx = idx;
4828a7d6542SBram Moolenaar 	    }
4838a7d6542SBram Moolenaar 	    else
48440f4f7a4SBram Moolenaar 	    {
48540f4f7a4SBram Moolenaar 		imported->imp_type = ufunc->uf_func_type;
4868a7d6542SBram Moolenaar 		imported->imp_funcname = ufunc->uf_name;
4878a7d6542SBram Moolenaar 	    }
4888a7d6542SBram Moolenaar 	}
48940f4f7a4SBram Moolenaar     }
4901c991144SBram Moolenaar erret:
4911c991144SBram Moolenaar     ga_clear_strings(&names);
4921c991144SBram Moolenaar     vim_free(as_name);
4938a7d6542SBram Moolenaar     return cmd_end;
4948a7d6542SBram Moolenaar }
4958a7d6542SBram Moolenaar 
496c82a5b5dSBram Moolenaar /*
497c82a5b5dSBram Moolenaar  * Declare a script-local variable without init: "let var: type".
498c82a5b5dSBram Moolenaar  * "const" is an error since the value is missing.
499c82a5b5dSBram Moolenaar  * Returns a pointer to after the type.
500c82a5b5dSBram Moolenaar  */
501c82a5b5dSBram Moolenaar     char_u *
502c82a5b5dSBram Moolenaar vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
503c82a5b5dSBram Moolenaar {
504c82a5b5dSBram Moolenaar     char_u	    *p;
505c82a5b5dSBram Moolenaar     char_u	    *name;
506c82a5b5dSBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
507c82a5b5dSBram Moolenaar     type_T	    *type;
508c82a5b5dSBram Moolenaar     int		    called_emsg_before = called_emsg;
509c82a5b5dSBram Moolenaar     typval_T	    init_tv;
510c82a5b5dSBram Moolenaar 
511c82a5b5dSBram Moolenaar     if (eap->cmdidx == CMD_const)
512c82a5b5dSBram Moolenaar     {
513bc4c5051SBram Moolenaar 	emsg(_(e_const_requires_a_value));
514c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
515c82a5b5dSBram Moolenaar     }
516c82a5b5dSBram Moolenaar 
517c82a5b5dSBram Moolenaar     // Check for valid starting character.
518c82a5b5dSBram Moolenaar     if (!eval_isnamec1(*arg))
519c82a5b5dSBram Moolenaar     {
520c82a5b5dSBram Moolenaar 	semsg(_(e_invarg2), arg);
521c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
522c82a5b5dSBram Moolenaar     }
523c82a5b5dSBram Moolenaar 
524984dddbeSBram Moolenaar     for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
5253b74b6b4SBram Moolenaar 	if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
526984dddbeSBram Moolenaar 	    break;
527c82a5b5dSBram Moolenaar 
528c82a5b5dSBram Moolenaar     if (*p != ':')
529c82a5b5dSBram Moolenaar     {
530bc4c5051SBram Moolenaar 	emsg(_(e_type_or_initialization_required));
531c82a5b5dSBram Moolenaar 	return arg + STRLEN(arg);
532c82a5b5dSBram Moolenaar     }
533984dddbeSBram Moolenaar     if (!VIM_ISWHITE(p[1]))
534984dddbeSBram Moolenaar     {
535*7cb6fc29SBram Moolenaar 	semsg(_(e_white_space_required_after_str), ":");
536984dddbeSBram Moolenaar 	return arg + STRLEN(arg);
537984dddbeSBram Moolenaar     }
538c82a5b5dSBram Moolenaar     name = vim_strnsave(arg, p - arg);
539c82a5b5dSBram Moolenaar 
540c82a5b5dSBram Moolenaar     // parse type
541c82a5b5dSBram Moolenaar     p = skipwhite(p + 1);
542c82a5b5dSBram Moolenaar     type = parse_type(&p, &si->sn_type_list);
543c82a5b5dSBram Moolenaar     if (called_emsg != called_emsg_before)
544f3decc58SBram Moolenaar     {
545f3decc58SBram Moolenaar 	vim_free(name);
546c82a5b5dSBram Moolenaar 	return p;
547f3decc58SBram Moolenaar     }
548c82a5b5dSBram Moolenaar 
549c82a5b5dSBram Moolenaar     // Create the variable with 0/NULL value.
550c82a5b5dSBram Moolenaar     CLEAR_FIELD(init_tv);
551c82a5b5dSBram Moolenaar     init_tv.v_type = type->tt_type;
552c82a5b5dSBram Moolenaar     set_var_const(name, type, &init_tv, FALSE, 0);
553c82a5b5dSBram Moolenaar 
554c82a5b5dSBram Moolenaar     vim_free(name);
555c82a5b5dSBram Moolenaar     return p;
556c82a5b5dSBram Moolenaar }
557c82a5b5dSBram Moolenaar 
55834db91f7SBram Moolenaar /*
55934db91f7SBram Moolenaar  * Check if the type of script variable "dest" allows assigning "value".
56034db91f7SBram Moolenaar  */
561c785b9a7SBram Moolenaar     int
56234db91f7SBram Moolenaar check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
56334db91f7SBram Moolenaar {
56434db91f7SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
56534db91f7SBram Moolenaar     int		    idx;
56634db91f7SBram Moolenaar 
56781e17fbeSBram Moolenaar     if (si->sn_version != SCRIPT_VERSION_VIM9)
56881e17fbeSBram Moolenaar 	// legacy script doesn't store variable types
56981e17fbeSBram Moolenaar 	return OK;
57081e17fbeSBram Moolenaar 
57134db91f7SBram Moolenaar     // Find the svar_T in sn_var_vals.
57234db91f7SBram Moolenaar     for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
57334db91f7SBram Moolenaar     {
57434db91f7SBram Moolenaar 	svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
57534db91f7SBram Moolenaar 
57634db91f7SBram Moolenaar 	if (sv->sv_tv == dest)
57734db91f7SBram Moolenaar 	{
57834db91f7SBram Moolenaar 	    if (sv->sv_const)
579c785b9a7SBram Moolenaar 	    {
58034db91f7SBram Moolenaar 		semsg(_(e_readonlyvar), name);
581c785b9a7SBram Moolenaar 		return FAIL;
582c785b9a7SBram Moolenaar 	    }
5834cdb13ceSBram Moolenaar 	    return check_typval_type(sv->sv_type, value);
58434db91f7SBram Moolenaar 	}
58534db91f7SBram Moolenaar     }
58634db91f7SBram Moolenaar     iemsg("check_script_var_type(): not found");
587c785b9a7SBram Moolenaar     return OK; // not really
58834db91f7SBram Moolenaar }
589c82a5b5dSBram Moolenaar 
5908a7d6542SBram Moolenaar #endif // FEAT_EVAL
591