xref: /vim-8.2.3635/src/vim9script.c (revision ceb56ddb)
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) || defined(PROTO)
17 
18 #include "vim9.h"
19 
20 static char e_needs_vim9[] = N_("E1042: export can only be used in vim9script");
21 
22     int
23 in_vim9script(void)
24 {
25     // Do not go up the stack, a ":function" inside vim9script uses legacy
26     // syntax.  "sc_version" is also set when compiling a ":def" function in
27     // legacy script.
28     return current_sctx.sc_version == SCRIPT_VERSION_VIM9;
29 }
30 
31 /*
32  * ":vim9script".
33  */
34     void
35 ex_vim9script(exarg_T *eap)
36 {
37     scriptitem_T    *si;
38 
39     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
40     {
41 	emsg(_("E1038: vim9script can only be used in a script"));
42 	return;
43     }
44     si = SCRIPT_ITEM(current_sctx.sc_sid);
45     if (si->sn_had_command)
46     {
47 	emsg(_("E1039: vim9script must be the first command in a script"));
48 	return;
49     }
50     current_sctx.sc_version = SCRIPT_VERSION_VIM9;
51     si->sn_version = SCRIPT_VERSION_VIM9;
52     si->sn_had_command = TRUE;
53 
54     if (STRCMP(p_cpo, CPO_VIM) != 0)
55     {
56 	si->sn_save_cpo = p_cpo;
57 	p_cpo = vim_strsave((char_u *)CPO_VIM);
58     }
59 }
60 
61 /*
62  * ":export let Name: type"
63  * ":export const Name: type"
64  * ":export def Name(..."
65  * ":export class Name ..."
66  *
67  * ":export {Name, ...}"
68  */
69     void
70 ex_export(exarg_T *eap)
71 {
72     if (!in_vim9script())
73     {
74 	emsg(_(e_needs_vim9));
75 	return;
76     }
77 
78     eap->cmd = eap->arg;
79     (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
80     switch (eap->cmdidx)
81     {
82 	case CMD_let:
83 	case CMD_const:
84 	case CMD_def:
85 	// case CMD_class:
86 	    is_export = TRUE;
87 	    do_cmdline(eap->cmd, eap->getline, eap->cookie,
88 						DOCMD_VERBOSE + DOCMD_NOWAIT);
89 
90 	    // The command will reset "is_export" when exporting an item.
91 	    if (is_export)
92 	    {
93 		emsg(_("E1044: export with invalid argument"));
94 		is_export = FALSE;
95 	    }
96 	    break;
97 	default:
98 	    emsg(_("E1043: Invalid command after :export"));
99 	    break;
100     }
101 }
102 
103 /*
104  * Add a new imported item entry to the current script.
105  */
106     static imported_T *
107 new_imported(garray_T *gap)
108 {
109     if (ga_grow(gap, 1) == OK)
110 	return ((imported_T *)gap->ga_data + gap->ga_len++);
111     return NULL;
112 }
113 
114 /*
115  * Free all imported items in script "sid".
116  */
117     void
118 free_imports(int sid)
119 {
120     scriptitem_T    *si = SCRIPT_ITEM(sid);
121     int		    idx;
122 
123     for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
124     {
125 	imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
126 
127 	vim_free(imp->imp_name);
128     }
129     ga_clear(&si->sn_imports);
130     ga_clear(&si->sn_var_vals);
131     clear_type_list(&si->sn_type_list);
132 }
133 
134 /*
135  * ":import Item from 'filename'"
136  * ":import Item as Alias from 'filename'"
137  * ":import {Item} from 'filename'".
138  * ":import {Item as Alias} from 'filename'"
139  * ":import {Item, Item} from 'filename'"
140  * ":import {Item, Item as Alias} from 'filename'"
141  *
142  * ":import * as Name from 'filename'"
143  */
144     void
145 ex_import(exarg_T *eap)
146 {
147     char_u	*cmd_end;
148     evalarg_T	evalarg;
149 
150     if (!getline_equal(eap->getline, eap->cookie, getsourceline))
151     {
152 	emsg(_("E1094: import can only be used in a script"));
153 	return;
154     }
155     fill_evalarg_from_eap(&evalarg, eap, eap->skip);
156 
157     cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
158 							       &evalarg, NULL);
159     if (cmd_end != NULL)
160 	eap->nextcmd = check_nextcmd(cmd_end);
161     clear_evalarg(&evalarg, eap);
162 }
163 
164 /*
165  * Find an exported item in "sid" matching the name at "*argp".
166  * When it is a variable return the index.
167  * When it is a user function return "*ufunc".
168  * When not found returns -1 and "*ufunc" is NULL.
169  */
170     int
171 find_exported(
172 	int	    sid,
173 	char_u	    *name,
174 	ufunc_T	    **ufunc,
175 	type_T	    **type)
176 {
177     int		idx = -1;
178     svar_T	*sv;
179     scriptitem_T *script = SCRIPT_ITEM(sid);
180 
181     // find name in "script"
182     // TODO: also find script-local user function
183     idx = get_script_item_idx(sid, name, FALSE);
184     if (idx >= 0)
185     {
186 	sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
187 	if (!sv->sv_export)
188 	{
189 	    semsg(_("E1049: Item not exported in script: %s"), name);
190 	    return -1;
191 	}
192 	*type = sv->sv_type;
193 	*ufunc = NULL;
194     }
195     else
196     {
197 	char_u	buffer[200];
198 	char_u	*funcname;
199 
200 	// it could be a user function.
201 	if (STRLEN(name) < sizeof(buffer) - 10)
202 	    funcname = buffer;
203 	else
204 	{
205 	    funcname = alloc(STRLEN(name) + 10);
206 	    if (funcname == NULL)
207 		return -1;
208 	}
209 	funcname[0] = K_SPECIAL;
210 	funcname[1] = KS_EXTRA;
211 	funcname[2] = (int)KE_SNR;
212 	sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
213 	*ufunc = find_func(funcname, FALSE, NULL);
214 	if (funcname != buffer)
215 	    vim_free(funcname);
216 
217 	if (*ufunc == NULL)
218 	{
219 	    semsg(_("E1048: Item not found in script: %s"), name);
220 	    return -1;
221 	}
222     }
223 
224     return idx;
225 }
226 
227 /*
228  * Handle an ":import" command and add the resulting imported_T to "gap", when
229  * not NULL, or script "import_sid" sn_imports.
230  * Returns a pointer to after the command or NULL in case of failure
231  */
232     char_u *
233 handle_import(
234 	char_u	    *arg_start,
235 	garray_T    *gap,
236 	int	    import_sid,
237 	evalarg_T   *evalarg,
238 	void	    *cctx)
239 {
240     char_u	*arg = arg_start;
241     char_u	*cmd_end = NULL;
242     char_u	*as_name = NULL;
243     int		ret = FAIL;
244     typval_T	tv;
245     int		sid = -1;
246     int		res;
247     garray_T	names;
248     static char e_import_syntax[] = N_("E1047: syntax error in import");
249 
250     ga_init2(&names, sizeof(char_u *), 10);
251     if (*arg == '{')
252     {
253 	// "import {item, item} from ..."
254 	arg = skipwhite_and_linebreak(arg + 1, evalarg);
255 	for (;;)
256 	{
257 	    char_u  *p = arg;
258 	    int	    had_comma = FALSE;
259 
260 	    while (eval_isnamec(*arg))
261 		++arg;
262 	    if (p == arg)
263 		break;
264 	    if (ga_grow(&names, 1) == FAIL)
265 		goto erret;
266 	    ((char_u **)names.ga_data)[names.ga_len] =
267 						      vim_strnsave(p, arg - p);
268 	    ++names.ga_len;
269 	    if (*arg == ',')
270 	    {
271 		had_comma = TRUE;
272 		++arg;
273 	    }
274 	    arg = skipwhite_and_linebreak(arg, evalarg);
275 	    if (*arg == '}')
276 	    {
277 		arg = skipwhite_and_linebreak(arg + 1, evalarg);
278 		break;
279 	    }
280 	    if (!had_comma)
281 	    {
282 		emsg(_("E1046: Missing comma in import"));
283 		goto erret;
284 	    }
285 	}
286 	if (names.ga_len == 0)
287 	{
288 	    emsg(_(e_import_syntax));
289 	    goto erret;
290 	}
291     }
292     else
293     {
294 	// "import Name from ..."
295 	// "import * as Name from ..."
296 	// "import item [as Name] from ..."
297 	arg = skipwhite_and_linebreak(arg, evalarg);
298 	if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
299 	    arg = skipwhite_and_linebreak(arg + 1, evalarg);
300 	else if (eval_isnamec1(*arg))
301 	{
302 	    char_u  *p = arg;
303 
304 	    while (eval_isnamec(*arg))
305 		++arg;
306 	    if (ga_grow(&names, 1) == FAIL)
307 		goto erret;
308 	    ((char_u **)names.ga_data)[names.ga_len] =
309 						      vim_strnsave(p, arg - p);
310 	    ++names.ga_len;
311 	    arg = skipwhite_and_linebreak(arg, evalarg);
312 	}
313 	else
314 	{
315 	    emsg(_(e_import_syntax));
316 	    goto erret;
317 	}
318 
319 	if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
320 	{
321 	    char_u *p;
322 
323 	    // skip over "as Name "; no line break allowed after "as"
324 	    arg = skipwhite(arg + 2);
325 	    p = arg;
326 	    if (eval_isnamec1(*arg))
327 		while (eval_isnamec(*arg))
328 		    ++arg;
329 	    if (check_defined(p, arg - p, cctx) == FAIL)
330 		goto erret;
331 	    as_name = vim_strnsave(p, arg - p);
332 	    arg = skipwhite_and_linebreak(arg, evalarg);
333 	}
334 	else if (*arg_start == '*')
335 	{
336 	    emsg(_("E1045: Missing \"as\" after *"));
337 	    goto erret;
338 	}
339     }
340 
341     if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
342     {
343 	emsg(_("E1070: Missing \"from\""));
344 	goto erret;
345     }
346 
347     arg = skipwhite_and_linebreak(arg + 4, evalarg);
348     tv.v_type = VAR_UNKNOWN;
349     // TODO: should we accept any expression?
350     if (*arg == '\'')
351 	ret = eval_lit_string(&arg, &tv, TRUE);
352     else if (*arg == '"')
353 	ret = eval_string(&arg, &tv, TRUE);
354     if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
355     {
356 	emsg(_("E1071: Invalid string after \"from\""));
357 	goto erret;
358     }
359     cmd_end = arg;
360 
361     /*
362      * find script file
363      */
364     if (*tv.vval.v_string == '.')
365     {
366 	size_t		len;
367 	scriptitem_T	*si = SCRIPT_ITEM(current_sctx.sc_sid);
368 	char_u		*tail = gettail(si->sn_name);
369 	char_u		*from_name;
370 
371 	// Relative to current script: "./name.vim", "../../name.vim".
372 	len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
373 	from_name = alloc((int)len);
374 	if (from_name == NULL)
375 	{
376 	    clear_tv(&tv);
377 	    goto erret;
378 	}
379 	vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
380 	add_pathsep(from_name);
381 	STRCAT(from_name, tv.vval.v_string);
382 	simplify_filename(from_name);
383 
384 	res = do_source(from_name, FALSE, DOSO_NONE, &sid);
385 	vim_free(from_name);
386     }
387     else if (mch_isFullName(tv.vval.v_string))
388     {
389 	// Absolute path: "/tmp/name.vim"
390 	res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
391     }
392     else
393     {
394 	size_t	    len = 7 + STRLEN(tv.vval.v_string) + 1;
395 	char_u	    *from_name;
396 
397 	// Find file in "import" subdirs in 'runtimepath'.
398 	from_name = alloc((int)len);
399 	if (from_name == NULL)
400 	{
401 	    clear_tv(&tv);
402 	    goto erret;
403 	}
404 	vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
405 	res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
406 	vim_free(from_name);
407     }
408 
409     if (res == FAIL || sid <= 0)
410     {
411 	semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
412 	clear_tv(&tv);
413 	goto erret;
414     }
415     clear_tv(&tv);
416 
417     if (*arg_start == '*')
418     {
419 	imported_T *imported = new_imported(gap != NULL ? gap
420 					: &SCRIPT_ITEM(import_sid)->sn_imports);
421 
422 	if (imported == NULL)
423 	    goto erret;
424 	imported->imp_name = as_name;
425 	as_name = NULL;
426 	imported->imp_sid = sid;
427 	imported->imp_all = TRUE;
428     }
429     else
430     {
431 	int i;
432 
433 	arg = arg_start;
434 	if (*arg == '{')
435 	    arg = skipwhite(arg + 1);
436 	for (i = 0; i < names.ga_len; ++i)
437 	{
438 	    char_u	*name = ((char_u **)names.ga_data)[i];
439 	    int		idx;
440 	    imported_T	*imported;
441 	    ufunc_T	*ufunc = NULL;
442 	    type_T	*type;
443 
444 	    idx = find_exported(sid, name, &ufunc, &type);
445 
446 	    if (idx < 0 && ufunc == NULL)
447 		goto erret;
448 
449 	    if (check_defined(name, STRLEN(name), cctx) == FAIL)
450 		goto erret;
451 
452 	    imported = new_imported(gap != NULL ? gap
453 				       : &SCRIPT_ITEM(import_sid)->sn_imports);
454 	    if (imported == NULL)
455 		goto erret;
456 
457 	    // TODO: check for "as" following
458 	    // imported->imp_name = vim_strsave(as_name);
459 	    imported->imp_name = name;
460 	    ((char_u **)names.ga_data)[i] = NULL;
461 	    imported->imp_sid = sid;
462 	    if (idx >= 0)
463 	    {
464 		imported->imp_type = type;
465 		imported->imp_var_vals_idx = idx;
466 	    }
467 	    else
468 		imported->imp_funcname = ufunc->uf_name;
469 	}
470     }
471 erret:
472     ga_clear_strings(&names);
473     vim_free(as_name);
474     return cmd_end;
475 }
476 
477 /*
478  * Declare a script-local variable without init: "let var: type".
479  * "const" is an error since the value is missing.
480  * Returns a pointer to after the type.
481  */
482     char_u *
483 vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
484 {
485     char_u	    *p;
486     char_u	    *name;
487     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
488     type_T	    *type;
489     int		    called_emsg_before = called_emsg;
490     typval_T	    init_tv;
491 
492     if (eap->cmdidx == CMD_const)
493     {
494 	emsg(_(e_const_req_value));
495 	return arg + STRLEN(arg);
496     }
497 
498     // Check for valid starting character.
499     if (!eval_isnamec1(*arg))
500     {
501 	semsg(_(e_invarg2), arg);
502 	return arg + STRLEN(arg);
503     }
504 
505     for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
506 	if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
507 	    break;
508 
509     if (*p != ':')
510     {
511 	emsg(_(e_type_req));
512 	return arg + STRLEN(arg);
513     }
514     if (!VIM_ISWHITE(p[1]))
515     {
516 	semsg(_(e_white_after), ":");
517 	return arg + STRLEN(arg);
518     }
519     name = vim_strnsave(arg, p - arg);
520 
521     // parse type
522     p = skipwhite(p + 1);
523     type = parse_type(&p, &si->sn_type_list);
524     if (called_emsg != called_emsg_before)
525     {
526 	vim_free(name);
527 	return p;
528     }
529 
530     // Create the variable with 0/NULL value.
531     CLEAR_FIELD(init_tv);
532     init_tv.v_type = type->tt_type;
533     set_var_const(name, type, &init_tv, FALSE, 0);
534 
535     vim_free(name);
536     return p;
537 }
538 
539 /*
540  * Check if the type of script variable "dest" allows assigning "value".
541  */
542     int
543 check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
544 {
545     scriptitem_T    *si = SCRIPT_ITEM(current_sctx.sc_sid);
546     int		    idx;
547 
548     // Find the svar_T in sn_var_vals.
549     for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
550     {
551 	svar_T    *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
552 
553 	if (sv->sv_tv == dest)
554 	{
555 	    if (sv->sv_const)
556 	    {
557 		semsg(_(e_readonlyvar), name);
558 		return FAIL;
559 	    }
560 	    return check_type(sv->sv_type, typval2type(value), TRUE);
561 	}
562     }
563     iemsg("check_script_var_type(): not found");
564     return OK; // not really
565 }
566 
567 #endif // FEAT_EVAL
568