xref: /vim-8.2.3635/src/vim9script.c (revision 09689a02)
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 static char e_needs_vim9[] = N_("E1042: import/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 {
3521b9e977SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
36*09689a02SBram Moolenaar     garray_T	    *gap;
37*09689a02SBram Moolenaar     garray_T	    func_ga;
38*09689a02SBram Moolenaar     int		    idx;
39*09689a02SBram Moolenaar     ufunc_T	    *ufunc;
408a7d6542SBram Moolenaar 
418a7d6542SBram Moolenaar     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
428a7d6542SBram Moolenaar     {
438a7d6542SBram Moolenaar 	emsg(_("E1038: vim9script can only be used in a script"));
448a7d6542SBram Moolenaar 	return;
458a7d6542SBram Moolenaar     }
468a7d6542SBram Moolenaar     if (si->sn_had_command)
478a7d6542SBram Moolenaar     {
488a7d6542SBram Moolenaar 	emsg(_("E1039: vim9script must be the first command in a script"));
498a7d6542SBram Moolenaar 	return;
508a7d6542SBram Moolenaar     }
518a7d6542SBram Moolenaar     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
528a7d6542SBram Moolenaar     si->sn_version = SCRIPT_VERSION_VIM9;
538a7d6542SBram Moolenaar     si->sn_had_command = TRUE;
54*09689a02SBram Moolenaar     ga_init2(&func_ga, sizeof(ufunc_T *), 20);
558a7d6542SBram Moolenaar 
568a7d6542SBram Moolenaar     if (STRCMP(p_cpo, CPO_VIM) != 0)
578a7d6542SBram Moolenaar     {
588a7d6542SBram Moolenaar 	si->sn_save_cpo = p_cpo;
598a7d6542SBram Moolenaar 	p_cpo = vim_strsave((char_u *)CPO_VIM);
608a7d6542SBram Moolenaar     }
61*09689a02SBram Moolenaar 
62*09689a02SBram Moolenaar     // Make a pass through the script to find:
63*09689a02SBram Moolenaar     // - function declarations
64*09689a02SBram Moolenaar     // - variable and constant declarations
65*09689a02SBram Moolenaar     // - imports
66*09689a02SBram Moolenaar     // The types are recognized, so that they can be used when compiling a
67*09689a02SBram Moolenaar     // function.
68*09689a02SBram Moolenaar     gap = source_get_line_ga(eap->cookie);
69*09689a02SBram Moolenaar     for (;;)
70*09689a02SBram Moolenaar     {
71*09689a02SBram Moolenaar 	char_u	    *line;
72*09689a02SBram Moolenaar 	char_u	    *p;
73*09689a02SBram Moolenaar 
74*09689a02SBram Moolenaar 	if (ga_grow(gap, 1) == FAIL)
75*09689a02SBram Moolenaar 	    return;
76*09689a02SBram Moolenaar 	line = eap->getline(':', eap->cookie, 0, TRUE);
77*09689a02SBram Moolenaar 	if (line == NULL)
78*09689a02SBram Moolenaar 	    break;
79*09689a02SBram Moolenaar 	((char_u **)(gap->ga_data))[gap->ga_len++] = line;
80*09689a02SBram Moolenaar 	line = skipwhite(line);
81*09689a02SBram Moolenaar 	p = line;
82*09689a02SBram Moolenaar 	if (checkforcmd(&p, "function", 2) || checkforcmd(&p, "def", 3))
83*09689a02SBram Moolenaar 	{
84*09689a02SBram Moolenaar 	    int		    lnum_start = SOURCING_LNUM - 1;
85*09689a02SBram Moolenaar 
86*09689a02SBram Moolenaar 	    // Handle :function and :def by calling def_function().
87*09689a02SBram Moolenaar 	    // It will read upto the matching :endded or :endfunction.
88*09689a02SBram Moolenaar 	    eap->cmdidx = *line == 'f' ? CMD_function : CMD_def;
89*09689a02SBram Moolenaar 	    eap->cmd = line;
90*09689a02SBram Moolenaar 	    eap->arg = p;
91*09689a02SBram Moolenaar 	    eap->forceit = FALSE;
92*09689a02SBram Moolenaar 	    ufunc = def_function(eap, NULL, NULL, FALSE);
93*09689a02SBram Moolenaar 
94*09689a02SBram Moolenaar 	    if (ufunc != NULL && *line == 'd' && ga_grow(&func_ga, 1) == OK)
95*09689a02SBram Moolenaar 	    {
96*09689a02SBram Moolenaar 		// Add the function to the list of :def functions, so that it
97*09689a02SBram Moolenaar 		// can be referenced by index.  It's compiled below.
98*09689a02SBram Moolenaar 		add_def_function(ufunc);
99*09689a02SBram Moolenaar 		((ufunc_T **)(func_ga.ga_data))[func_ga.ga_len++] = ufunc;
100*09689a02SBram Moolenaar 	    }
101*09689a02SBram Moolenaar 
102*09689a02SBram Moolenaar 	    // Store empty lines in place of the function, we don't need to
103*09689a02SBram Moolenaar 	    // process it again.
104*09689a02SBram Moolenaar 	    vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]);
105*09689a02SBram Moolenaar 	    if (ga_grow(gap, SOURCING_LNUM - lnum_start) == OK)
106*09689a02SBram Moolenaar 		while (lnum_start < SOURCING_LNUM)
107*09689a02SBram Moolenaar 		{
108*09689a02SBram Moolenaar 		    // getsourceline() will skip over NULL lines.
109*09689a02SBram Moolenaar 		    ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL;
110*09689a02SBram Moolenaar 		    ++lnum_start;
111*09689a02SBram Moolenaar 		}
112*09689a02SBram Moolenaar 	}
113*09689a02SBram Moolenaar 	else if (checkforcmd(&p, "let", 3) || checkforcmd(&p, "const", 4))
114*09689a02SBram Moolenaar 	{
115*09689a02SBram Moolenaar 	    eap->cmd = line;
116*09689a02SBram Moolenaar 	    eap->arg = p;
117*09689a02SBram Moolenaar 	    eap->forceit = FALSE;
118*09689a02SBram Moolenaar 	    eap->cmdidx = *line == 'l' ? CMD_let: CMD_const;
119*09689a02SBram Moolenaar 
120*09689a02SBram Moolenaar 	    // The command will be executed again, it's OK to redefine the
121*09689a02SBram Moolenaar 	    // variable then.
122*09689a02SBram Moolenaar 	    ex_let_const(eap, TRUE);
123*09689a02SBram Moolenaar 	}
124*09689a02SBram Moolenaar 	else if (checkforcmd(&p, "import", 3))
125*09689a02SBram Moolenaar 	{
126*09689a02SBram Moolenaar 	    eap->arg = p;
127*09689a02SBram Moolenaar 	    ex_import(eap);
128*09689a02SBram Moolenaar 
129*09689a02SBram Moolenaar 	    // Store empty line, we don't need to process the command again.
130*09689a02SBram Moolenaar 	    vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]);
131*09689a02SBram Moolenaar 	    ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL;
132*09689a02SBram Moolenaar 	}
133*09689a02SBram Moolenaar     }
134*09689a02SBram Moolenaar 
135*09689a02SBram Moolenaar     // Compile the :def functions.
136*09689a02SBram Moolenaar     for (idx = 0; idx < func_ga.ga_len; ++idx)
137*09689a02SBram Moolenaar     {
138*09689a02SBram Moolenaar 	ufunc = ((ufunc_T **)(func_ga.ga_data))[idx];
139*09689a02SBram Moolenaar 	compile_def_function(ufunc, FALSE, NULL);
140*09689a02SBram Moolenaar     }
141*09689a02SBram Moolenaar     ga_clear(&func_ga);
142*09689a02SBram Moolenaar 
143*09689a02SBram Moolenaar     // Return to process the commands at the script level.
144*09689a02SBram Moolenaar     source_use_line_ga(eap->cookie);
1458a7d6542SBram Moolenaar }
1468a7d6542SBram Moolenaar 
1478a7d6542SBram Moolenaar /*
1488a7d6542SBram Moolenaar  * ":export let Name: type"
1498a7d6542SBram Moolenaar  * ":export const Name: type"
1508a7d6542SBram Moolenaar  * ":export def Name(..."
1518a7d6542SBram Moolenaar  * ":export class Name ..."
1528a7d6542SBram Moolenaar  *
1538a7d6542SBram Moolenaar  * ":export {Name, ...}"
1548a7d6542SBram Moolenaar  */
1558a7d6542SBram Moolenaar     void
156*09689a02SBram Moolenaar ex_export(exarg_T *eap)
1578a7d6542SBram Moolenaar {
1588a7d6542SBram Moolenaar     if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
1598a7d6542SBram Moolenaar     {
1608a7d6542SBram Moolenaar 	emsg(_(e_needs_vim9));
1618a7d6542SBram Moolenaar 	return;
1628a7d6542SBram Moolenaar     }
1638a7d6542SBram Moolenaar 
1648a7d6542SBram Moolenaar     eap->cmd = eap->arg;
1658a7d6542SBram Moolenaar     (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
1668a7d6542SBram Moolenaar     switch (eap->cmdidx)
1678a7d6542SBram Moolenaar     {
1688a7d6542SBram Moolenaar 	case CMD_let:
1698a7d6542SBram Moolenaar 	case CMD_const:
1708a7d6542SBram Moolenaar 	case CMD_def:
1718a7d6542SBram Moolenaar 	// case CMD_class:
1728a7d6542SBram Moolenaar 	    is_export = TRUE;
1738a7d6542SBram Moolenaar 	    do_cmdline(eap->cmd, eap->getline, eap->cookie,
1748a7d6542SBram Moolenaar 						DOCMD_VERBOSE + DOCMD_NOWAIT);
1758a7d6542SBram Moolenaar 
1768a7d6542SBram Moolenaar 	    // The command will reset "is_export" when exporting an item.
1778a7d6542SBram Moolenaar 	    if (is_export)
1788a7d6542SBram Moolenaar 	    {
1798a7d6542SBram Moolenaar 		emsg(_("E1044: export with invalid argument"));
1808a7d6542SBram Moolenaar 		is_export = FALSE;
1818a7d6542SBram Moolenaar 	    }
1828a7d6542SBram Moolenaar 	    break;
1838a7d6542SBram Moolenaar 	default:
1848a7d6542SBram Moolenaar 	    emsg(_("E1043: Invalid command after :export"));
1858a7d6542SBram Moolenaar 	    break;
1868a7d6542SBram Moolenaar     }
1878a7d6542SBram Moolenaar }
1888a7d6542SBram Moolenaar 
1898a7d6542SBram Moolenaar /*
1908a7d6542SBram Moolenaar  * Add a new imported item entry to the current script.
1918a7d6542SBram Moolenaar  */
1928a7d6542SBram Moolenaar     static imported_T *
1938a7d6542SBram Moolenaar new_imported(garray_T *gap)
1948a7d6542SBram Moolenaar {
1958a7d6542SBram Moolenaar     if (ga_grow(gap, 1) == OK)
1968a7d6542SBram Moolenaar 	return ((imported_T *)gap->ga_data + gap->ga_len++);
1978a7d6542SBram Moolenaar     return NULL;
1988a7d6542SBram Moolenaar }
1998a7d6542SBram Moolenaar 
2008a7d6542SBram Moolenaar /*
2018a7d6542SBram Moolenaar  * Free all imported items in script "sid".
2028a7d6542SBram Moolenaar  */
2038a7d6542SBram Moolenaar     void
2048a7d6542SBram Moolenaar free_imports(int sid)
2058a7d6542SBram Moolenaar {
20621b9e977SBram Moolenaar     scriptitem_T    *si = SCRIPT_ITEM(sid);
2078a7d6542SBram Moolenaar     int		    idx;
2088a7d6542SBram Moolenaar 
2098a7d6542SBram Moolenaar     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
2108a7d6542SBram Moolenaar     {
21120431c9dSBram Moolenaar 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
2128a7d6542SBram Moolenaar 
2138a7d6542SBram Moolenaar 	vim_free(imp->imp_name);
2148a7d6542SBram Moolenaar     }
2158a7d6542SBram Moolenaar     ga_clear(&si->sn_imports);
21620431c9dSBram Moolenaar     ga_clear(&si->sn_var_vals);
21720431c9dSBram Moolenaar     ga_clear(&si->sn_type_list);
2188a7d6542SBram Moolenaar }
2198a7d6542SBram Moolenaar 
2208a7d6542SBram Moolenaar /*
2218a7d6542SBram Moolenaar  * ":import Item from 'filename'"
2228a7d6542SBram Moolenaar  * ":import Item as Alias from 'filename'"
2238a7d6542SBram Moolenaar  * ":import {Item} from 'filename'".
2248a7d6542SBram Moolenaar  * ":import {Item as Alias} from 'filename'"
2258a7d6542SBram Moolenaar  * ":import {Item, Item} from 'filename'"
2268a7d6542SBram Moolenaar  * ":import {Item, Item as Alias} from 'filename'"
2278a7d6542SBram Moolenaar  *
2288a7d6542SBram Moolenaar  * ":import * as Name from 'filename'"
2298a7d6542SBram Moolenaar  */
2308a7d6542SBram Moolenaar     void
2318a7d6542SBram Moolenaar ex_import(exarg_T *eap)
2328a7d6542SBram Moolenaar {
2338a7d6542SBram Moolenaar     if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
2348a7d6542SBram Moolenaar 	emsg(_(e_needs_vim9));
2358a7d6542SBram Moolenaar     else
2368a7d6542SBram Moolenaar     {
2375269bd2aSBram Moolenaar 	char_u *cmd_end = handle_import(eap->arg, NULL,
2385269bd2aSBram Moolenaar 						    current_sctx.sc_sid, NULL);
2398a7d6542SBram Moolenaar 
2408a7d6542SBram Moolenaar 	if (cmd_end != NULL)
2418a7d6542SBram Moolenaar 	    eap->nextcmd = check_nextcmd(cmd_end);
2428a7d6542SBram Moolenaar     }
2438a7d6542SBram Moolenaar }
2448a7d6542SBram Moolenaar 
2458a7d6542SBram Moolenaar /*
246f2d5c240SBram Moolenaar  * Find an exported item in "sid" matching the name at "*argp".
247f2d5c240SBram Moolenaar  * When it is a variable return the index.
248f2d5c240SBram Moolenaar  * When it is a user function return "*ufunc".
249f2d5c240SBram Moolenaar  * When not found returns -1 and "*ufunc" is NULL.
250f2d5c240SBram Moolenaar  */
251f2d5c240SBram Moolenaar     int
252f2d5c240SBram Moolenaar find_exported(
253f2d5c240SBram Moolenaar 	int	    sid,
254f2d5c240SBram Moolenaar 	char_u	    **argp,
255f2d5c240SBram Moolenaar 	int	    *name_len,
256f2d5c240SBram Moolenaar 	ufunc_T	    **ufunc,
257f2d5c240SBram Moolenaar 	type_T	    **type)
258f2d5c240SBram Moolenaar {
259f2d5c240SBram Moolenaar     char_u	*name = *argp;
260f2d5c240SBram Moolenaar     char_u	*arg = *argp;
261f2d5c240SBram Moolenaar     int		cc;
262f2d5c240SBram Moolenaar     int		idx = -1;
263f2d5c240SBram Moolenaar     svar_T	*sv;
264f2d5c240SBram Moolenaar     scriptitem_T *script = SCRIPT_ITEM(sid);
265f2d5c240SBram Moolenaar 
266f2d5c240SBram Moolenaar     // isolate one name
267fa29c8abSBram Moolenaar     while (eval_isnamec(*arg))
268f2d5c240SBram Moolenaar 	++arg;
269f2d5c240SBram Moolenaar     *name_len = (int)(arg - name);
270f2d5c240SBram Moolenaar 
271f2d5c240SBram Moolenaar     // find name in "script"
272f2d5c240SBram Moolenaar     // TODO: also find script-local user function
273f2d5c240SBram Moolenaar     cc = *arg;
274f2d5c240SBram Moolenaar     *arg = NUL;
275f2d5c240SBram Moolenaar     idx = get_script_item_idx(sid, name, FALSE);
276f2d5c240SBram Moolenaar     if (idx >= 0)
277f2d5c240SBram Moolenaar     {
278f2d5c240SBram Moolenaar 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
279f2d5c240SBram Moolenaar 	if (!sv->sv_export)
280f2d5c240SBram Moolenaar 	{
281f2d5c240SBram Moolenaar 	    semsg(_("E1049: Item not exported in script: %s"), name);
282f2d5c240SBram Moolenaar 	    *arg = cc;
283f2d5c240SBram Moolenaar 	    return -1;
284f2d5c240SBram Moolenaar 	}
285f2d5c240SBram Moolenaar 	*type = sv->sv_type;
286f2d5c240SBram Moolenaar 	*ufunc = NULL;
287f2d5c240SBram Moolenaar     }
288f2d5c240SBram Moolenaar     else
289f2d5c240SBram Moolenaar     {
290f2d5c240SBram Moolenaar 	char_u	buffer[200];
291f2d5c240SBram Moolenaar 	char_u	*funcname;
292f2d5c240SBram Moolenaar 
293f2d5c240SBram Moolenaar 	// it could be a user function.
294f2d5c240SBram Moolenaar 	if (STRLEN(name) < sizeof(buffer) - 10)
295f2d5c240SBram Moolenaar 	    funcname = buffer;
296f2d5c240SBram Moolenaar 	else
297f2d5c240SBram Moolenaar 	{
298f2d5c240SBram Moolenaar 	    funcname = alloc(STRLEN(name) + 10);
299f2d5c240SBram Moolenaar 	    if (funcname == NULL)
300f2d5c240SBram Moolenaar 	    {
301f2d5c240SBram Moolenaar 		*arg = cc;
302f2d5c240SBram Moolenaar 		return -1;
303f2d5c240SBram Moolenaar 	    }
304f2d5c240SBram Moolenaar 	}
305f2d5c240SBram Moolenaar 	funcname[0] = K_SPECIAL;
306f2d5c240SBram Moolenaar 	funcname[1] = KS_EXTRA;
307f2d5c240SBram Moolenaar 	funcname[2] = (int)KE_SNR;
308f2d5c240SBram Moolenaar 	sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
3094c17ad94SBram Moolenaar 	*ufunc = find_func(funcname, FALSE, NULL);
310f2d5c240SBram Moolenaar 	if (funcname != buffer)
311f2d5c240SBram Moolenaar 	    vim_free(funcname);
312f2d5c240SBram Moolenaar 
313f2d5c240SBram Moolenaar 	if (*ufunc == NULL)
314f2d5c240SBram Moolenaar 	{
315f2d5c240SBram Moolenaar 	    semsg(_("E1048: Item not found in script: %s"), name);
316f2d5c240SBram Moolenaar 	    *arg = cc;
317f2d5c240SBram Moolenaar 	    return -1;
318f2d5c240SBram Moolenaar 	}
319f2d5c240SBram Moolenaar     }
320f2d5c240SBram Moolenaar     *arg = cc;
321f2d5c240SBram Moolenaar     arg = skipwhite(arg);
322f2d5c240SBram Moolenaar     *argp = arg;
323f2d5c240SBram Moolenaar 
324f2d5c240SBram Moolenaar     return idx;
325f2d5c240SBram Moolenaar }
326f2d5c240SBram Moolenaar 
327f2d5c240SBram Moolenaar /*
3288a7d6542SBram Moolenaar  * Handle an ":import" command and add the resulting imported_T to "gap", when
3298a7d6542SBram Moolenaar  * not NULL, or script "import_sid" sn_imports.
3308a7d6542SBram Moolenaar  * Returns a pointer to after the command or NULL in case of failure
3318a7d6542SBram Moolenaar  */
3328a7d6542SBram Moolenaar     char_u *
3335269bd2aSBram Moolenaar handle_import(char_u *arg_start, garray_T *gap, int import_sid, void *cctx)
3348a7d6542SBram Moolenaar {
3358a7d6542SBram Moolenaar     char_u	*arg = arg_start;
3368a7d6542SBram Moolenaar     char_u	*cmd_end;
3378a7d6542SBram Moolenaar     char_u	*as_ptr = NULL;
3388a7d6542SBram Moolenaar     char_u	*from_ptr;
3398a7d6542SBram Moolenaar     int		as_len = 0;
3408a7d6542SBram Moolenaar     int		ret = FAIL;
3418a7d6542SBram Moolenaar     typval_T	tv;
3428a7d6542SBram Moolenaar     int		sid = -1;
3438a7d6542SBram Moolenaar     int		res;
3448a7d6542SBram Moolenaar 
3458a7d6542SBram Moolenaar     if (*arg == '{')
3468a7d6542SBram Moolenaar     {
3478a7d6542SBram Moolenaar 	// skip over {item} list
3488a7d6542SBram Moolenaar 	while (*arg != NUL && *arg != '}')
3498a7d6542SBram Moolenaar 	    ++arg;
3508a7d6542SBram Moolenaar 	if (*arg == '}')
3518a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
3528a7d6542SBram Moolenaar     }
3538a7d6542SBram Moolenaar     else
3548a7d6542SBram Moolenaar     {
3558a7d6542SBram Moolenaar 	if (*arg == '*')
3568a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
357fa29c8abSBram Moolenaar 	else if (eval_isnamec1(*arg))
3588a7d6542SBram Moolenaar 	{
359fa29c8abSBram Moolenaar 	    while (eval_isnamec(*arg))
3608a7d6542SBram Moolenaar 		++arg;
3618a7d6542SBram Moolenaar 	    arg = skipwhite(arg);
3628a7d6542SBram Moolenaar 	}
3638a7d6542SBram Moolenaar 	if (STRNCMP("as", arg, 2) == 0 && VIM_ISWHITE(arg[2]))
3648a7d6542SBram Moolenaar 	{
3658a7d6542SBram Moolenaar 	    // skip over "as Name "
3668a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 2);
3678a7d6542SBram Moolenaar 	    as_ptr = arg;
368fa29c8abSBram Moolenaar 	    if (eval_isnamec1(*arg))
369fa29c8abSBram Moolenaar 		while (eval_isnamec(*arg))
3708a7d6542SBram Moolenaar 		    ++arg;
3718a7d6542SBram Moolenaar 	    as_len = (int)(arg - as_ptr);
3728a7d6542SBram Moolenaar 	    arg = skipwhite(arg);
3735269bd2aSBram Moolenaar 	    if (check_defined(as_ptr, as_len, cctx) == FAIL)
3745269bd2aSBram Moolenaar 		return NULL;
3758a7d6542SBram Moolenaar 	}
3768a7d6542SBram Moolenaar 	else if (*arg_start == '*')
3778a7d6542SBram Moolenaar 	{
3788a7d6542SBram Moolenaar 	    emsg(_("E1045: Missing \"as\" after *"));
3798a7d6542SBram Moolenaar 	    return NULL;
3808a7d6542SBram Moolenaar 	}
3818a7d6542SBram Moolenaar     }
3828a7d6542SBram Moolenaar     if (STRNCMP("from", arg, 4) != 0 || !VIM_ISWHITE(arg[4]))
3838a7d6542SBram Moolenaar     {
384fa29c8abSBram Moolenaar 	emsg(_("E1070: Missing \"from\""));
3858a7d6542SBram Moolenaar 	return NULL;
3868a7d6542SBram Moolenaar     }
3878a7d6542SBram Moolenaar     from_ptr = arg;
3888a7d6542SBram Moolenaar     arg = skipwhite(arg + 4);
3898a7d6542SBram Moolenaar     tv.v_type = VAR_UNKNOWN;
3908a7d6542SBram Moolenaar     // TODO: should we accept any expression?
3918a7d6542SBram Moolenaar     if (*arg == '\'')
3928a7d6542SBram Moolenaar 	ret = get_lit_string_tv(&arg, &tv, TRUE);
3938a7d6542SBram Moolenaar     else if (*arg == '"')
3948a7d6542SBram Moolenaar 	ret = get_string_tv(&arg, &tv, TRUE);
3958a7d6542SBram Moolenaar     if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
3968a7d6542SBram Moolenaar     {
397fa29c8abSBram Moolenaar 	emsg(_("E1071: Invalid string after \"from\""));
3988a7d6542SBram Moolenaar 	return NULL;
3998a7d6542SBram Moolenaar     }
4008a7d6542SBram Moolenaar     cmd_end = arg;
4018a7d6542SBram Moolenaar 
4028a7d6542SBram Moolenaar     // find script tv.vval.v_string
4038a7d6542SBram Moolenaar     if (*tv.vval.v_string == '.')
4048a7d6542SBram Moolenaar     {
4058a7d6542SBram Moolenaar 	size_t		len;
40621b9e977SBram Moolenaar 	scriptitem_T	*si = SCRIPT_ITEM(current_sctx.sc_sid);
4078a7d6542SBram Moolenaar 	char_u		*tail = gettail(si->sn_name);
4088a7d6542SBram Moolenaar 	char_u		*from_name;
4098a7d6542SBram Moolenaar 
4108a7d6542SBram Moolenaar 	// Relative to current script: "./name.vim", "../../name.vim".
4118a7d6542SBram Moolenaar 	len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
4128a7d6542SBram Moolenaar 	from_name = alloc((int)len);
4138a7d6542SBram Moolenaar 	if (from_name == NULL)
4148a7d6542SBram Moolenaar 	{
4158a7d6542SBram Moolenaar 	    clear_tv(&tv);
4168a7d6542SBram Moolenaar 	    return NULL;
4178a7d6542SBram Moolenaar 	}
4188a7d6542SBram Moolenaar 	vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
4198a7d6542SBram Moolenaar 	add_pathsep(from_name);
4208a7d6542SBram Moolenaar 	STRCAT(from_name, tv.vval.v_string);
4218a7d6542SBram Moolenaar 	simplify_filename(from_name);
4228a7d6542SBram Moolenaar 
4238a7d6542SBram Moolenaar 	res = do_source(from_name, FALSE, DOSO_NONE, &sid);
4248a7d6542SBram Moolenaar 	vim_free(from_name);
4258a7d6542SBram Moolenaar     }
4268a7d6542SBram Moolenaar     else if (mch_isFullName(tv.vval.v_string))
4278a7d6542SBram Moolenaar     {
4288a7d6542SBram Moolenaar 	// Absolute path: "/tmp/name.vim"
4298a7d6542SBram Moolenaar 	res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
4308a7d6542SBram Moolenaar     }
4318a7d6542SBram Moolenaar     else
4328a7d6542SBram Moolenaar     {
4338a7d6542SBram Moolenaar 	size_t	    len = 7 + STRLEN(tv.vval.v_string) + 1;
4348a7d6542SBram Moolenaar 	char_u	    *from_name;
4358a7d6542SBram Moolenaar 
4368a7d6542SBram Moolenaar 	// Find file in "import" subdirs in 'runtimepath'.
4378a7d6542SBram Moolenaar 	from_name = alloc((int)len);
4388a7d6542SBram Moolenaar 	if (from_name == NULL)
4398a7d6542SBram Moolenaar 	{
4408a7d6542SBram Moolenaar 	    clear_tv(&tv);
4418a7d6542SBram Moolenaar 	    return NULL;
4428a7d6542SBram Moolenaar 	}
4438a7d6542SBram Moolenaar 	vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
4448a7d6542SBram Moolenaar 	res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
4458a7d6542SBram Moolenaar 	vim_free(from_name);
4468a7d6542SBram Moolenaar     }
4478a7d6542SBram Moolenaar 
4488a7d6542SBram Moolenaar     if (res == FAIL || sid <= 0)
4498a7d6542SBram Moolenaar     {
4508a7d6542SBram Moolenaar 	semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
4518a7d6542SBram Moolenaar 	clear_tv(&tv);
4528a7d6542SBram Moolenaar 	return NULL;
4538a7d6542SBram Moolenaar     }
4548a7d6542SBram Moolenaar     clear_tv(&tv);
4558a7d6542SBram Moolenaar 
4568a7d6542SBram Moolenaar     if (*arg_start == '*')
4578a7d6542SBram Moolenaar     {
4588a7d6542SBram Moolenaar 	imported_T *imported = new_imported(gap != NULL ? gap
45921b9e977SBram Moolenaar 					: &SCRIPT_ITEM(import_sid)->sn_imports);
4608a7d6542SBram Moolenaar 
4618a7d6542SBram Moolenaar 	if (imported == NULL)
4628a7d6542SBram Moolenaar 	    return NULL;
4638a7d6542SBram Moolenaar 	imported->imp_name = vim_strnsave(as_ptr, as_len);
4648a7d6542SBram Moolenaar 	imported->imp_sid = sid;
4658a7d6542SBram Moolenaar 	imported->imp_all = TRUE;
4668a7d6542SBram Moolenaar     }
4678a7d6542SBram Moolenaar     else
4688a7d6542SBram Moolenaar     {
4698a7d6542SBram Moolenaar 	arg = arg_start;
4708a7d6542SBram Moolenaar 	if (*arg == '{')
4718a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
4728a7d6542SBram Moolenaar 	for (;;)
4738a7d6542SBram Moolenaar 	{
4748a7d6542SBram Moolenaar 	    char_u	*name = arg;
4758a7d6542SBram Moolenaar 	    int		name_len;
4768a7d6542SBram Moolenaar 	    int		idx;
4778a7d6542SBram Moolenaar 	    imported_T	*imported;
478f2d5c240SBram Moolenaar 	    ufunc_T	*ufunc = NULL;
479f2d5c240SBram Moolenaar 	    type_T	*type;
4808a7d6542SBram Moolenaar 
481f2d5c240SBram Moolenaar 	    idx = find_exported(sid, &arg, &name_len, &ufunc, &type);
4828a7d6542SBram Moolenaar 
483f2d5c240SBram Moolenaar 	    if (idx < 0 && ufunc == NULL)
4848a7d6542SBram Moolenaar 		return NULL;
4858a7d6542SBram Moolenaar 
4865269bd2aSBram Moolenaar 	    if (check_defined(name, name_len, cctx) == FAIL)
4875269bd2aSBram Moolenaar 		return NULL;
4885269bd2aSBram Moolenaar 
4898a7d6542SBram Moolenaar 	    imported = new_imported(gap != NULL ? gap
49021b9e977SBram Moolenaar 				       : &SCRIPT_ITEM(import_sid)->sn_imports);
4918a7d6542SBram Moolenaar 	    if (imported == NULL)
4928a7d6542SBram Moolenaar 		return NULL;
4938a7d6542SBram Moolenaar 
4948a7d6542SBram Moolenaar 	    // TODO: check for "as" following
4958a7d6542SBram Moolenaar 	    // imported->imp_name = vim_strnsave(as_ptr, as_len);
4968a7d6542SBram Moolenaar 	    imported->imp_name = vim_strnsave(name, name_len);
4978a7d6542SBram Moolenaar 	    imported->imp_sid = sid;
4988a7d6542SBram Moolenaar 	    if (idx >= 0)
4998a7d6542SBram Moolenaar 	    {
500f2d5c240SBram Moolenaar 		imported->imp_type = type;
5018a7d6542SBram Moolenaar 		imported->imp_var_vals_idx = idx;
5028a7d6542SBram Moolenaar 	    }
5038a7d6542SBram Moolenaar 	    else
5048a7d6542SBram Moolenaar 		imported->imp_funcname = ufunc->uf_name;
5058a7d6542SBram Moolenaar 
5068a7d6542SBram Moolenaar 	    arg = skipwhite(arg);
5078a7d6542SBram Moolenaar 	    if (*arg_start != '{')
5088a7d6542SBram Moolenaar 		break;
5098a7d6542SBram Moolenaar 	    if (*arg == '}')
5108a7d6542SBram Moolenaar 	    {
5118a7d6542SBram Moolenaar 		arg = skipwhite(arg + 1);
5128a7d6542SBram Moolenaar 		break;
5138a7d6542SBram Moolenaar 	    }
5148a7d6542SBram Moolenaar 
5158a7d6542SBram Moolenaar 	    if (*arg != ',')
5168a7d6542SBram Moolenaar 	    {
5178a7d6542SBram Moolenaar 		emsg(_("E1046: Missing comma in import"));
5188a7d6542SBram Moolenaar 		return NULL;
5198a7d6542SBram Moolenaar 	    }
5208a7d6542SBram Moolenaar 	    arg = skipwhite(arg + 1);
5218a7d6542SBram Moolenaar 	}
5228a7d6542SBram Moolenaar 	if (arg != from_ptr)
5238a7d6542SBram Moolenaar 	{
524fa29c8abSBram Moolenaar 	    // cannot happen, just in case the above has a flaw
5258a7d6542SBram Moolenaar 	    emsg(_("E1047: syntax error in import"));
5268a7d6542SBram Moolenaar 	    return NULL;
5278a7d6542SBram Moolenaar 	}
5288a7d6542SBram Moolenaar     }
5298a7d6542SBram Moolenaar     return cmd_end;
5308a7d6542SBram Moolenaar }
5318a7d6542SBram Moolenaar 
5328a7d6542SBram Moolenaar #endif // FEAT_EVAL
533