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